You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 18:47:12