Web API中基于其他服务注册具体DbContext的依赖注入问题
解决方案
你的问题出在AddDbContext的配置方式错误,正确的做法是利用AddDbContext的重载方法,直接在配置委托中访问服务提供者,从而获取已注册的IDatabaseOptions来动态配置数据库上下文。
修正后的完整注册代码
首先保留你现有的IDatabaseOptions和DatabaseOptions注册:
services.Configure<DatabaseOptions>(configuration.GetSection(nameof(DatabaseOptions))); services.AddSingleton<IDatabaseOptions>(serviceProvider => serviceProvider.GetRequiredService<IOptions<DatabaseOptions>>().Value);
然后修改ApplicationDbContext的注册代码,使用接受IServiceProvider的重载:
services.AddDbContext<ApplicationDbContext>((serviceProvider, optionsBuilder) => { var dbOptions = serviceProvider.GetRequiredService<IDatabaseOptions>(); switch (dbOptions.DatabaseType) { case DatabaseType.MSSQL: optionsBuilder.UseSqlServer(dbOptions.ConnectionString); break; case DatabaseType.POSTGRESQL: optionsBuilder.UseNpgsql(dbOptions.ConnectionString); break; default: throw new InvalidOperationException($"不支持的数据库类型:{dbOptions.DatabaseType}"); } });
为什么原来的代码无效
你之前错误地使用了AddOptions<DbContextOptionsBuilder>()链式调用,这并不是配置EF Core上下文的正确方式。AddDbContext内部已经负责管理DbContextOptions的配置,通过接受IServiceProvider的重载,你可以在配置上下文时直接访问容器中已注册的服务,完全不需要提前调用BuildServiceProvider。
可选简化:去掉IDatabaseOptions的单独注册
如果你不需要在其他地方直接注入IDatabaseOptions,可以简化注册步骤,直接通过IOptions<DatabaseOptions>获取配置:
services.Configure<DatabaseOptions>(configuration.GetSection(nameof(DatabaseOptions))); services.AddDbContext<ApplicationDbContext>((serviceProvider, optionsBuilder) => { var dbOptions = serviceProvider.GetRequiredService<IOptions<DatabaseOptions>>().Value; switch (dbOptions.DatabaseType) { case DatabaseType.MSSQL: optionsBuilder.UseSqlServer(dbOptions.ConnectionString); break; case DatabaseType.POSTGRESQL: optionsBuilder.UseNpgsql(dbOptions.ConnectionString); break; default: throw new InvalidOperationException($"不支持的数据库类型:{dbOptions.DatabaseType}"); } });
这样可以省去单独注册IDatabaseOptions为单例的步骤,直接利用.NET原生的IOptions模式获取配置值。
内容的提问来源于stack exchange,提问作者Astro
相关产品推荐
相关产品推荐

