.NET 8升级至9后集成测试出现多数据库提供者注册错误
解决方案:彻底清理EF服务并兼容测试与迁移
1. 重构DbContext注册逻辑,避免硬绑定SqlServer
不要在启动逻辑里直接硬编码注册SqlServer,改用配置驱动的条件注册,让生产和测试环境可无缝切换:
// Program.cs 或 Startup.cs builder.Services.AddDbContext<MyDbContext>((sp, options) => { var config = sp.GetRequiredService<IConfiguration>(); var dbProvider = config.GetValue<string>("DatabaseProvider"); if (dbProvider == "SqlServer") { options.UseSqlServer(config.GetConnectionString("DefaultConnection")); } else if (dbProvider == "InMemory") { options.UseInMemoryDatabase("TestDb"); } });
生产环境在appsettings.json里配置"DatabaseProvider": "SqlServer",测试环境对应改成"InMemory"即可,无需修改核心注册代码。
2. 在WebApplicationFactory中彻底移除SqlServer相关服务
如果必须在测试代码里动态替换(而非用配置切换),除了移除DbContextOptions<MyDbContext>,还要清理.NET9新增校验的数据库提供者服务:
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class { protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.ConfigureServices(services => { // 移除MyDbContext的配置选项 var dbContextOptionDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<MyDbContext>)); if (dbContextOptionDescriptor != null) { services.Remove(dbContextOptionDescriptor); } // 移除SqlServer数据库提供者服务(.NET9校验的核心) var sqlServerProvider = services.SingleOrDefault(d => d.ServiceType == typeof(IDatabaseProvider) && d.ImplementationType?.Name == "SqlServerDatabaseProvider"); if (sqlServerProvider != null) { services.Remove(sqlServerProvider); } // 注册InMemory版本的DbContext services.AddDbContext<MyDbContext>(options => { options.UseInMemoryDatabase("IntegrationTestDb"); options.LogTo(_ => false, LogLevel.Information); // 关闭冗余日志 }); // 初始化测试数据库 using var scope = services.BuildServiceProvider().CreateScope(); var testDb = scope.ServiceProvider.GetRequiredService<MyDbContext>(); testDb.Database.EnsureCreated(); }); } }
3. 修复EF迁移工具的IConfiguration注入问题
把配置逻辑从OnConfiguring移回服务注册后,按以下方式确保迁移工具正常工作:
- 保持DbContext的构造函数依赖
DbContextOptions<MyDbContext>(EF官方推荐方式):
public class MyDbContext : DbContext { public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { } // 可选:仅在未配置时兜底(比如本地单独调试DbContext) // protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) // { // if (!optionsBuilder.IsConfigured) // { // var config = new ConfigurationBuilder() // .AddJsonFile("appsettings.json") // .Build(); // optionsBuilder.UseSqlServer(config.GetConnectionString("DefaultConnection")); // } // } }
- 运行迁移命令时指定启动项目,工具会自动读取生产配置:
dotnet ef migrations add InitialCreate --project YourDataProject --startup-project YourWebProject
4. 简化方案:用环境变量直接切换
在测试项目的appsettings.json里添加配置:
{ "DatabaseProvider": "InMemory" }
这样启动测试时,Program里的注册逻辑会自动选择InMemory,无需手动移除服务,代码更简洁。
内容的提问来源于stack exchange,提问作者Victorio Berra
相关产品推荐
相关产品推荐

