c# - 在派生的 DbContext 中获取服务
问题描述
我有以下派生的 DbContext:
public class PowerDbContext : DbContext
{
readonly IDbAuthTokenService _authTokenService;
readonly string _connectionString;
readonly bool _useManagedIdentity;
public MyDbContext(DbContextOptions<NyDbContext> options) : base(options)
{
_authTokenService = this.GetService<IOptionsSnapshot<AzureSqlAuthTokenService>>().Value;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var connection = new SqlConnection(_connectionString);
connection.AccessToken = _authTokenService.GetTokenAsync().GetAwaiter().GetResult();
}
在 Startup.cs 中:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<IDbAuthTokenService, AzureSqlAuthTokenService>();
services.AddEntityFrameworkSqlServer();
services.AddEntityFrameworkProxies();
services.AddDbContextPool<MyDbContext>((serviceProvider, optionsBuilder) =>
{
optionsBuilder.UseLazyLoadingProxies();
optionsBuilder.UseSqlServer(connectionString);
optionsBuilder.UseInternalServiceProvider(serviceProvider);
}, Configuration.GetAppSetting<int>("PoolSize"));
...
}
但我收到以下错误:
System.InvalidOperationException : Unable to resolve service for type 'Microsoft.Extensions.Options.IOptionsSnapshot<Myproject.Database.Services.AzureSqlAuthTokenService>'. This is often because no database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
如何让 DbContext 解析令牌服务OnConfiguring()
?
更新:要清楚,我不能使用构造函数注入,因为 AddDbContextPool() 要求我派生的 DbContext 有一个只有一个参数的构造函数 (DbContextOptions)
解决方案
对于注入本身,一个简单的构造函数注入应该这样做:
public MyDbContext(DbContextOptions<NyDbContext> options, IOptionsSnapshot<AzureSqlAuthTokenService> authTokenService) : base(options)
...
但是,在我看来(至少从您提供的代码来看)您从未配置IOptionsSnapshot<AzureSqlAuthTokenService>
过。相反,您配置IDbAuthTokenService
指向AzureSqlAuthTokenService
实现的服务。我不是 100% 确定你想走哪条路,但我看到了两种可能性:
1)注入你的IDbAuthTokenService
服务:
public MyDbContext(DbContextOptions<NyDbContext> options, IDbAuthTokenService authTokenService) : base(options)
...
2)配置IOptionsSnapshot,然后注入它(见文档):
Startup.cs:
public void ConfigureServices(IServiceCollection services)
...
services.Configure<MyAzureTokenOptions>(Configuration.GetSection("Proper:Config:Section"));
...
数据库上下文:
public MyDbContext(DbContextOptions<NyDbContext> options, IOptionsSnapshot<MyAzureTokenOptions> azureTokenOptions) : base(options)
...
编辑:
我错过了您正在使用 DbContext 池的事实。是的,你是对的——在这种情况下,构造函数注入不起作用。但是其余的答案仍然适用:您注册了一个IDbAuthTokenService
服务(通过它的AzureSqlAuthTokenService
实现),但尝试IOptionsSnapshot<AzureSqlAuthTokenService>
从服务提供者那里检索。换句话说,您正在寻找未在 DI 中注册的服务(或选项快照),这就是您收到该特定错误的原因。如上所述修复服务(或选项快照)的检索或注册。
重要提示:
如果它是您想要的服务,您应该了解一下 DbContext 池的工作原理。要点是在服务请求而不是销毁 DbContext 实例之后,它的状态被重置并返回到池中。这意味着它实际上是单例的。由于您不能将作用域(或瞬态)依赖项注入单例主体,因此您的依赖项也必须是单例的。这意味着:
public void ConfigureServices(IServiceCollection services)
...
services.AddSingleton<IDbAuthTokenService, AzureSqlAuthTokenService>();
如果你AzureSqlAuthTokenService
自己依赖于其他作用域的依赖,你要么在依赖链中传播相同的原则(如果这对于所说的依赖是合理的),或者从池中切换并省去一些麻烦。
推荐阅读
- ios - Swift 5.3 未在 xcode 12 构建设置中显示
- python - 如何在 pyfiglet python3 中获取所有可用的字体
- android - Android 不会自动完成
- java - 我可以将字符串中的字段值放入 Apache Solr 中的自定义 TokenFilter 中吗?
- javascript - JS如何处理键盘事件
- html - 未找到 CSS 选择器错误。?VScode 中的警告
- android - 如何在 Android 中舍入 RadioButton?
- javascript - 使用 JavaScript、localStorage 和 Php 计算当前用户的超链接点击次数
- javascript - 使用箭头函数引用与内联箭头函数时 javascript 中的混淆行为
- android - 邮递员表单编码文件上传不适用于改造