J W*_*ezy 1 c# dependency-injection azure-sql-database azure-web-app-service .net-5
问题:
我们有一个 .NET 5 WPF 应用程序,它有一个 EntityFramework Core 实体类文件DbEntities,它实现了DbContext. 我们在实例化它时使用构造函数注入。我们使用的选项之一是AddInterceptors将访问令牌附加到SqlConnection. 拦截器被称为AzureAuthenticationInterceptor。在注册服务时,我们希望传入ServiceProvider以便它在拦截器构造函数中可用,可用于获取实现访问令牌内存缓存的服务。
原因是我们有一个包含 50 多个类的项目,这些类都使用同一个DbEntities文件,在构造函数中使用 0 个参数。这已升级到 .NET 5,其中避免了依赖注入,因为需要将其应用于所有表单。因此, 以DbEntities具有 的形式实例化new DbEntities();。
但是,在这种情况下,我们正在实现访问令牌缓存,需要将其注册为服务。否则,如果我们每次创建 new 时都实例化缓存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))
;
}
Run Code Online (Sandbox Code Playgroud)
数据库实体.cs
public DbEntities() :
base(new DbContextOptionsBuilder<DbEntities>()
.UseSqlServer(ConfigurationManager.ConnectionStrings["DbEntities"].ConnectionString)
.AddInterceptors(new AzureAuthenticationInterceptor())
.Options)
{ }
Run Code Online (Sandbox Code Playgroud)
AzureAuthenticationInterceptor.cs
public AzureAuthenticationInterceptor(IServiceProvider objServiceProvider)
{
this.IAzureSqlTokenProvider = (IAzureSqlTokenProvider)objServiceProvider.GetService(typeof(IAzureSqlTokenProvider));
}
Run Code Online (Sandbox Code Playgroud)
首先,避免注入IServiceProvider,这是一种代码异味,会导致设计不佳。
重构 AzureAuthenticationInterceptor.cs
public AzureAuthenticationInterceptor(IAzureSqlTokenProvider tokenProvider) {
this.IAzureSqlTokenProvider = tokenProvider;
}
Run Code Online (Sandbox Code Playgroud)
这样就可以根据需要注入显式依赖项
//...
.AddSingleton<AzureAuthenticationInterceptor>()
//...
Run Code Online (Sandbox Code Playgroud)
在配置 DbEntities 时解析拦截器时
//...
services.AddDbContext<DbEntities>((provider, options) => {
options.UseSqlServer(Configuration.GetConnectionString("<connection-string-name>"));
options.AddInterceptors(provider.GetRequiredService<AzureAuthenticationInterceptor>());
});
//...
Run Code Online (Sandbox Code Playgroud)
请注意,如果您使用默认构造函数手动初始化上下文,即:new DbEntities();那么这绕过了通过构造函数注入应用依赖注入的机会。