.NET Core 3.0迁移后添加EF Core迁移时无法创建ApplicationDbContext实例
这个错误在EF Core迁移流程里挺常见的,核心原因是迁移工具没法自动解析你的ApplicationDbContext依赖项,或者找不到合适的构造函数来实例化它。结合你贴的代码来看,问题出在ApplicationDbContext有两个构造函数,其中一个依赖IServiceProvider,而迁移工具在设计时运行时没法自动注入这个服务。
下面给你几个可行的解决办法:
方法一:让迁移工具通过启动项目解析服务
如果你的Web项目是启动项目,且ApplicationDbContext的配置都在Startup里,可以试试这两步:
- 打开Package Manager Console,确保启动项目选的是包含Startup.cs的Web项目,同时把默认项目设为存放
ApplicationDbContext的Infrastructure项目。 - 执行迁移命令时显式指定启动项目:
Add-Migration InitialCreate -StartupProject YourWebProjectName -Project Infrastructure
不过这种方法有时候会受项目结构或工具版本影响,更稳妥的是下面的方法。
方法二:实现IDesignTimeDbContextFactory接口
这个接口是EF Core专门为设计时(比如迁移操作)创建DbContext实例设计的,实现后迁移工具会优先用这个工厂来创建实例,完全不需要依赖WebHost的服务配置。
在你的Infrastructure项目里新增一个类:
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; using System.IO; public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext> { public ApplicationDbContext CreateDbContext(string[] args) { // 构建配置,读取Web项目里的appsettings.json IConfigurationRoot configuration = new ConfigurationBuilder() .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../YourWebProjectName")) .AddJsonFile("appsettings.json") .Build(); // 配置DbContext连接字符串和迁移程序集 var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>(); optionsBuilder.UseSqlServer( configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly("Infrastructure")); // 用无额外依赖的构造函数实例化DbContext return new ApplicationDbContext(optionsBuilder.Options); } }
注意把YourWebProjectName换成你实际的Web项目名称,这样才能正确读取到配置文件。添加这个类后,再执行迁移命令就不会报错了。
方法三:简化DbContext构造函数
如果IServiceProvider只在运行时用到,迁移过程完全用不上,可以调整构造函数逻辑:保留只接受DbContextOptions的构造函数作为默认,把IServiceProvider改成属性注入的方式,这样迁移工具就能直接实例化DbContext了。
修改后的ApplicationDbContext代码:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, ILocalizationDbContext { public IServiceProvider ServiceProvider { get; set; } // 改成属性注入 // 供迁移工具和运行时使用的基础构造函数 public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } // 运行时专用构造函数,依赖注入容器会自动注入IServiceProvider public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IServiceProvider serviceProvider) : base(options) { ServiceProvider = serviceProvider; } }
不过这种方法需要确保你的依赖注入容器支持属性注入,相比工厂方法灵活性稍差一些。
试试上面的方法,应该就能顺利执行Add-Migration命令了。
内容的提问来源于stack exchange,提问作者John

