EF Core执行update-database报未找到引用设计时服务如何解决
在包管理器控制台执行update-database -verbose命令时,SQL Server未生成预期数据库对象,命令末尾返回如下日志:
Using context 'TutoringContext'. Finding design-time services for provider 'Microsoft.EntityFrameworkCore.SqlServer'... Using design-time services from provider 'Microsoft.EntityFrameworkCore.SqlServer'. Finding design-time services referenced by assembly 'LakeTutoringWebsite'... Finding design-time services referenced by assembly 'LakeTutoringWebsite'... No referenced design-time services were found. Finding IDesignTimeServices implementations in assembly 'LakeTutoringWebsite'... No design-time services were found.
当前项目基础信息:
- 框架版本:ASP.NET Core 3.1
- 已安装依赖:6.0.0版本
System.Configuration.Configuration包 - 已通过依赖注入完成
TutoringContext的服务注册,现有代码如下:
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddDbContext<TutoringContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LakeTutoringDatabase"))); } } public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); } public class TutoringContext : IdentityDbContext<IdentityUser> { public DbSet<Comment> Comments { get; set; } public TutoringContext(DbContextOptions<TutoringContext> options) : base(options) { } }
核心限制:已知DesignTimeDbContextFactory可解决该类迁移问题,但常规实现要求无参构造,无法传入IConfiguration读取配置文件中的连接字符串,需要在不硬编码连接字符串的前提下完成数据库迁移。
以下两种方案都不需要硬编码连接字符串,可根据项目情况选择:
方案一:实现可自动加载配置的
DesignTimeDbContextFactory
不需要依赖无参构造,直接在工厂方法内部手动构建配置对象,和运行时逻辑保持一致读取appsettings.json中的连接串即可,不需要修改现有DI注册代码,实现如下:using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; using System.IO; public class TutoringContextFactory : IDesignTimeDbContextFactory<TutoringContext> { public TutoringContext CreateDbContext(string[] args) { var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") // 需要读取环境变量配置时可放开下方注释 // .AddEnvironmentVariables() .Build(); var optionsBuilder = new DbContextOptionsBuilder<TutoringContext>(); optionsBuilder.UseSqlServer(configuration.GetConnectionString("LakeTutoringDatabase")); return new TutoringContext(optionsBuilder.Options); } }将该类放在
TutoringContext所在项目的根目录即可,EF Core设计时工具会自动扫描识别,不需要额外注册。需要提前将appsettings.json的文件属性设置为如果较新则复制,避免迁移执行时找不到配置文件。方案二:复用现有应用宿主的DI容器(无需编写额外工厂类)
EF Core 3.1的设计时工具原生支持从ASP.NET Core启动流程中自动获取已注册的DbContext,触发当前报错的最常见原因是项目未安装对应版本的设计时包。先通过NuGet为项目安装3.1.x版本的Microsoft.EntityFrameworkCore.Design包,注意包版本必须和项目EF Core运行时版本、ASP.NET Core框架版本对齐,禁止安装6.x及以上版本避免兼容性冲突。安装完成后重启Visual Studio,重新执行update-database命令即可。工具会自动调用现有Program类中的CreateHostBuilder方法构建完整宿主,直接从DI容器中读取已经配置好连接字符串的TutoringContext实例,全程不需要修改业务代码。
注意:当前安装的6.0.0版本System.Configuration.Configuration是.NET Framework体系下的配置组件,和ASP.NET Core 3.1采用的Microsoft.Extensions.Configuration配置体系不兼容,不要用它读取Core项目的配置文件,避免出现版本冲突或配置读取失败问题。
内容的提问来源于stack exchange,提问作者tournageCoding

