无法创建类型为'DbContext'的对象

65

当我尝试运行时

dotnet ef migration add Init

我遇到错误

无法创建类型为“IdentityContext”的对象。

我知道导致这个问题的原因。我想学习如何使用消息总线,并将其添加到我的项目中,所以我参加了一些课程并实现了它。当然,总线运行得很完美。但问题是我不再能够通过EF进行迁移。

我的Startup.cs之前是这样的。

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

现在它看起来是这样的。

public static void Main(string[] args)
{
  ServiceHost.Create<Startup>(args)
    .UseRabbitMq()
    .Build()
    .Run();
}

ServiceHost 类

public void Run() => _webHost.Run();

public static HostBuilder Create<TStartup>(string[] args) where TStartup : class
{
  Console.Title = typeof(TStartup).Namespace;
  var config = new ConfigurationBuilder()
    .AddEnvironmentVariables()
    .AddCommandLine(args)
    .Build();
  var webHostBuilder = WebHost.CreateDefaultBuilder()
    .UseConfiguration(config)
    .UseStartup<TStartup>();

  return new HostBuilder(webHostBuilder.Build());
}

有人能指导一下迁移为什么停止工作吗?在我看来,它应该可以正常工作,但实际上它并没有,所以我想我肯定错了。

当然,在我的Startup.cs中也有相应配置。

services.AddEntityFrameworkNpgsql().AddDbContext<IdentityContext>(options =>
    options.UseNpgsql(Configuration.GetConnectionString("IdentityConnection")));

编辑 IdentityContext 类:

  public class IdentityContext : DbContext
  {
    public IdentityContext(DbContextOptions<IdentityContext> options) : base(options)
    {
      while (!Debugger.IsAttached)
      {
        Thread.Sleep(100);
      }
    }
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
      modelBuilder.Entity<User>().HasIndex(user => user.Email).IsUnique();
      modelBuilder.Entity<User>().HasIndex(user => user.Username).IsUnique();
    }
  }

编辑2. 详细迁移

Using project '/home/msek/Projects/inz/CrossX/src/CrossX.Identity/CrossX.Identity.csproj'.
Using startup project '/home/msek/Projects/inz/CrossX/src/CrossX.Identity/CrossX.Identity.csproj'.
Writing '/home/msek/Projects/inz/CrossX/src/CrossX.Identity/obj/CrossX.Identity.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=/tmp/tmpCq3PQa.tmp /verbosity:quiet /nologo /home/msek/Projects/inz/CrossX/src/CrossX.Identity/CrossX.Identity.csproj
Writing '/home/msek/Projects/inz/CrossX/src/CrossX.Identity/obj/CrossX.Identity.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=/tmp/tmpR48yu8.tmp /verbosity:quiet /nologo /home/msek/Projects/inz/CrossX/src/CrossX.Identity/CrossX.Identity.csproj
dotnet build /home/msek/Projects/inz/CrossX/src/CrossX.Identity/CrossX.Identity.csproj /verbosity:quiet /nologo

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:01.17
dotnet exec --depsfile /home/msek/Projects/inz/CrossX/src/CrossX.Identity/bin/Debug/netcoreapp2.2/CrossX.Identity.deps.json --additionalprobingpath /home/msek/.nuget/packages --runtimeconfig /home/msek/Projects/inz/CrossX/src/CrossX.Identity/bin/Debug/netcoreapp2.2/CrossX.Identity.runtimeconfig.json /home/msek/.dotnet/tools/.store/dotnet-ef/2.2.2/dotnet-ef/2.2.2/tools/netcoreapp2.2/any/tools/netcoreapp2.0/any/ef.dll migrations add Init --assembly /home/msek/Projects/inz/CrossX/src/CrossX.Identity/bin/Debug/netcoreapp2.2/CrossX.Identity.dll --startup-assembly /home/msek/Projects/inz/CrossX/src/CrossX.Identity/bin/Debug/netcoreapp2.2/CrossX.Identity.dll --project-dir /home/msek/Projects/inz/CrossX/src/CrossX.Identity/ --language C# --working-dir /home/msek/Projects/inz/CrossX/src/CrossX.Identity --verbose --root-namespace CrossX.Identity
Using assembly 'CrossX.Identity'.
Using startup assembly 'CrossX.Identity'.
Using application base '/home/msek/Projects/inz/CrossX/src/CrossX.Identity/bin/Debug/netcoreapp2.2'.
Using working directory '/home/msek/Projects/inz/CrossX/src/CrossX.Identity'.
Using root namespace 'CrossX.Identity'.
Using project directory '/home/msek/Projects/inz/CrossX/src/CrossX.Identity/'.
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider...
Finding IWebHost accessor...
No CreateWebHostBuilder(string[]) method was found on type 'CrossX.Identity.Program'.
No application service provider was found.
Finding DbContext classes in the project...
Found DbContext 'IdentityContext'.
Microsoft.EntityFrameworkCore.Design.OperationException: Unable to create an object of type 'IdentityContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728 ---> System.MissingMethodException: No parameterless constructor defined for this object.
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean wrapExceptions, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean skipCheckThis, Boolean fillCache)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass12_3.<FindContextTypes>b__13()
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass12_3.<FindContextTypes>b__13()
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Unable to create an object of type 'IdentityContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

1
我一直使用以下方式将数据库上下文注册到Postgres中:services.AddDbContext(options => options.UseNpgsql(Configuration.GetConnectionString("IdentityConnection")));你能试一下并检查它是否有效吗? - carlos chourio
相同的错误。无法创建类型为“IdentityContext”的对象。 - Thou
你调试并检查了启动类是否被正确调用了吗? - carlos chourio
如果您将此更改为: .UseConfiguration(config) .UseStartup();``` 而不是 ```var webHostBuilder = WebHost.CreateDefaultBuilder() .UseConfiguration(config) .UseStartup(); return new HostBuilder(webHostBuilder.Build());``` - carlos chourio
遇到了同样的问题。原因是我从解决方案文件夹中运行CLI命令,如果是这样,必须定义启动项目:dotnet ef migrations add mymigration --startup-project .\Project-With-Startup.cs --project .\Project-With-Context --context MyContext - kaah
显示剩余2条评论
20个回答

83
如果您正在使用CLI,
当您有一个包含2个项目API/WebApp和DataAcess的解决方案时,您可以在命令行中传递选项。
My_Solution
       |DataAccess_Project
       |-- DbContext.cs
       |WebApp_Project
       |-- Startup.cs

切换到解决方案目录

CD My_Solution

dotnet ef migrations add InitialCreate --project DataAccess_Project --startup-project WebApp_Project

dotnet ef database update --project DataAccess_Project --startup-project WebApp_Project

2
谢谢,反过来说。第一个应该是 dotnet ef migrations add.... - MDave
@screamin 感谢你解释了一个解决方案中有多个项目的情况。你真是救了我的一天。 - MubarakZade
1
从.NET 5及更高版本开始,它将使用"Program.cs"而不是"Startup.cs"。在这里提一下,以免让那些现在遇到这个问题的人感到困惑。 - MubarakZade
这个解决了我的问题!谢谢! - undefined
如果您在多个项目中有多个DbContext,这也非常有用。 dotnet ef database update --context FinanceDbContext --project Finance.Data --startup-project MyApplication - undefined

33

我的问题是我没有将我的API项目设置为启动项目,所以它找不到任何 Startup.cs 或类似的文件。


2
您,先生,是一个非常出色的人 :) - Shane van Wyk
2
还要在程序包管理器控制台中将默认项目设置为数据项目,这对我很有帮助。 - Ivan Yurchenko
1
你是正确的!如果采用分层架构,你必须在包管理器控制台中选择具有DBContext的项目(正如Ivan Yurchenko所说的),并且具有"AddDbContext"方法的项目必须设置为启动项目(正如你所说的)。 - undefined

30

确保您具有没有参数的IdentityContext默认构造函数。它应该可以工作。


2
看似简单,但我经常忘记这一点(通常是将选项传递给唯一的构造函数)。 - doveryai
惊讶地发现带有默认参数的构造函数并不被视为无参构造函数。以下代码无法正常工作:public HumbleDbContext(string connectionString = "Server=.;Database=MyDb;Trusted_Connection=True;") - Luke Schoen

8
如果您正在使用新的.NET 5顶级代码功能,那么这很可能是迁移失败的原因。在Program类中使用顶级语句会使得EF工具无法访问它,因为它既没有命名空间也没有类名。
顶级语句:
Console.WriteLine("Hello, World!");

经典的Program类:

namespace MyApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

如果是这种情况,那么就回到经典模式。

谢谢,省了我很多时间!:d - Bulchsu

8

我附加了IdentityContext类。它扩展了DbContext。正如我所说,在我更改Startup.cs之前,它是可以工作的,因此我认为它被正确实现了。最后,在这个部分中。 - Thou
你正在使用哪个 .NET Core 版本? - JcMey3r

dotnet --version

2.2.105

- Thou
运行 add-migration initial -verbose 命令,查看它给出的底层错误。 - JcMey3r
1
尝试按照 https://learn.microsoft.com/en-gb/ef/core/miscellaneous/cli/dbcontext-creation 或 https://codingblast.com/entityframework-core-idesigntimedbcontextfactory/ 中所述的方式实现 IDesignTimeDbContextFactory。 - JcMey3r
显示剩余3条评论

6
在Program类中创建一个名为CreateWebHostBuilder的方法。将主方法体移动到该类中,并从Main方法调用该类。新实现如下所示:
public static void Main(string[] args)
{
    CreateWebHostBuilder(args).Build().Run();
}

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    ServiceHost.Create<Startup>(args)
                .UseRabbitMq()
                .Build()
                .Run();

ef工具查找CreateWebHostBuilder方法并在未找到任何方法时返回错误。


5

优化screamin的答案

我的项目结构如下所示

解决方案

  • X.Api
  • ...
  • ...
  • X.Repository

我的迁移位于X.Repository下,启动项目为X.Api。在一切设置正确且没有代码错误的情况下,我无法使用以下命令运行我的迁移:

dotnet ef migrations add CreateABCTable 

使用Screamin提供的解决方案后,我可以运行我的迁移。我使用了以下命令:

dotnet ef migrations add CreateABCTable --project X.Repository.csproj --startup-project ../X.Api/X.Api.csproj

谢谢,我的项目结构和你的一样,这使得 ef 迁移捆绑命令可以正常工作。 - Alexander Rojas
对我来说也是一样,我必须运行第二个命令,指定我想要针对dbContext的项目,并为启动项目提供参数。 - Eric Milliot-Martinez

3

为了帮助其他人,我添加了这个解决方案的变体。我需要在一个简单的控制台应用程序中创建一个迁移,并且必须向DbContext类添加一个空的默认.ctor。

public TestContext()
{
}

public TestContext(DbContextOptions<TestContext> options) : base(options)
{
}

这对我解决了问题,我以为它试图重新创建我的上下文类,但实际上它是在尝试实例化它。 - Zoey

3

如果你正在使用分层架构,那么可能会遇到这个问题。因此,你必须使用工厂设计模式。例如,你的上下文类必须像下面这样:

     public ModelContext(DbContextOptions<ModelContext> options) : base(options){}

       public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ModelContext>
    {

                DbContextOptionsBuilder<ModelContext> builder = new DbContextOptionsBuilder<ModelContext>();               
                IConfiguration config = new ConfigurationBuilder()
                .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(),"C:/Users/mücteba/source/repos/market/Market.API")) 
                       
                .AddJsonFile("appsettings.json")
                .Build();
           builder.UseSqlServer(config.GetConnectionString("SQLProvider"));
            return new ModelContext(builder.Options);
     }
  }
      DbSet<Personel> personels { get; set; }

如果您使用分层架构,那么这个类是必需的!!!


这是我的问题。 - Dave Shinkle

2

将您的 dbcontext 配置移到 builder.Build() 之前

builder.Services.AddDbContext(options => options.UseSqlite(builder.Configuration.GetConnectionString("Default")));

var app = builder.Build();


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接