c# - 是否可以将 ServiceProvider 传递给构造函数参数?
问题描述
问题:
我们有一个 .NET 5 WPF 应用程序,它有一个 EntityFramework Core 实体类文件DbEntities
,它实现了DbContext
. 我们在实例化它时使用构造函数注入。我们使用的选项之一是AddInterceptors
将访问令牌附加到SqlConnection
. 拦截器称为AzureAuthenticationInterceptor
. 注册服务时,我们希望传入 ,ServiceProvider
以便在拦截器构造函数中可用,它可以用于获取实现 Access Token 内存缓存的服务。
原因是我们有一个包含 50 多个类的项目,它们都使用同一个DbEntities
文件,该文件在构造函数中接受 0 个参数。这已升级到 .NET 5,其中避免了依赖注入,因为需要将其应用于所有表单。因此,DbEntities
以 的形式实例化new DbEntities();
。
但是,在这种情况下,我们正在实现一个访问令牌缓存,它需要注册为服务。否则,如果我们只是在每次创建新的时实例化缓存DbContext
,那么缓存将被清除。
访问令牌内存缓存使用此方法实现https://mderriey.com/2020/09/12/resolve-ef-core-interceptors-with-dependency-injection/
我们只想对内存令牌缓存使用依赖注入。我们认为是快捷方式的唯一方法是ServiceProvider
在拦截器的构造函数中传递 ,但它在方法中似乎不可用ConfigureServices
。
问题:
是否可以通过ServiceProvider
?如果没有,有没有其他方法可以在拦截器上实现依赖注入,而无需更改 50 个类文件?
程序.cs
Public static void Main()
{
...
Host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((context, builder) =>
{
builder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
})
.ConfigureServices((context, services) =>
{
Configuration = context.Configuration;
ConfigureServices(Configuration, services);
})
.Build();
...
}
private static void ConfigureServices(IConfiguration objConfiguration, IServiceCollection objServices)
{
objServices.AddMemoryCache()
.AddSingleton<IAzureSqlTokenProvider, AzureIdentityAzureSqlTokenProvider>()
.Decorate<IAzureSqlTokenProvider, CacheAzureSqlTokenProvider>()
.AddSingleton(new AzureAuthenticationInterceptor(IServiceProvider_NeededHere))
;
}
数据库实体.cs
public DbEntities() :
base(new DbContextOptionsBuilder<DbEntities>()
.UseSqlServer(ConfigurationManager.ConnectionStrings["DbEntities"].ConnectionString)
.AddInterceptors(new AzureAuthenticationInterceptor())
.Options)
{ }
AzureAuthenticationInterceptor.cs
public AzureAuthenticationInterceptor(IServiceProvider objServiceProvider)
{
this.IAzureSqlTokenProvider = (IAzureSqlTokenProvider)objServiceProvider.GetService(typeof(IAzureSqlTokenProvider));
}
解决方案
首先,避免注入IServiceProvider
,这是一种代码味道,会导致糟糕的设计。
重构 AzureAuthenticationInterceptor.cs
public AzureAuthenticationInterceptor(IAzureSqlTokenProvider tokenProvider) {
this.IAzureSqlTokenProvider = tokenProvider;
}
这样就可以根据需要注入显式依赖项
//...
.AddSingleton<AzureAuthenticationInterceptor>()
//...
在配置 DbEntities 时解析拦截器时
//...
services.AddDbContext<DbEntities>((provider, options) => {
options.UseSqlServer(Configuration.GetConnectionString("<connection-string-name>"));
options.AddInterceptors(provider.GetRequiredService<AzureAuthenticationInterceptor>());
});
//...
请注意,如果您使用默认构造函数手动初始化上下文,即:new DbEntities();
那么这会绕过通过构造函数注入应用依赖注入的机会。
推荐阅读
- javascript - 为什么我没有得到任何输出?
- javascript - 我尝试在 iOS 和 Android 设备上运行我的 React 应用时遇到此错误
- python - Pandas 将 NaN 从零插入到下一个有效值
- python - 如何在 Jupyter 笔记本中绘制素数
- asp.net - 如何设置 github 操作以使用 nunit 为 asp.net 应用程序运行单元测试?
- dependencies - 是否可以安装带有由 asdf 管理的依赖项的 Homebrew 软件包?
- javascript - 你能帮我编写一个新函数来计算循环播放的数量吗?
- algorithm - 与异常值匹配的最小成本
- firebase - 对于只对使用 Firestore 感兴趣的公司,gcloud 和 Firebase CLI 有什么区别
- java - 如何在 java eclipse 中向 JPanel 添加背景(URL)