我是来自 Java 世界的 C#/ASP 新手。我读过这篇文章:https://docs.asp.net/en/latest/fundamentals/dependency-injection.html#service-lifetimes-and-registration-options它明智地警告了与注入较小范围的依赖项相关的危险。不幸的是它没有解释如何在 C#/ASP 中解决这个问题。
Java中有一个Provider的概念
interface Provider<T> { T get(); }
除其他外,这有助于解决范围界定问题:
每当注册某种类型 T 的绑定时,我们都可以注入自动生成的 Provider 实例而不是 T,然后在需要时获取 T 的实例:自动生成的 Provider 确保我们获得适合该类型的实例当前范围(无论该范围是什么:HTTP 请求、HTTP 会话或其他自定义范围)。 ASP.NET core 中内置的标准 DI 框架没有这样的东西,但我认为在 C# 中它应该很容易实现,因为 C# 泛型不像 java 那样糟糕(https://docs.oracle.com/javase/tutorial/java/generics/erasure.html)。所以我创建了以下类:
public class Provider<T>: IProvider<T> {
private readonly IServiceProvider serviceProvider;
public Provider(IServiceProvider serviceProvider) {
this.serviceProvider = serviceProvider;
}
public T IProvider<T>.Get() {
return serviceProvider.GetService<T>();
}
}
我尝试按以下方式使用它:
public class SingletonService : ISingletonService {
private readonly IProvider<IScopedService> scopedServiceProvider;
public SingletonService(IProvider<IScopedService> scopedServiceProvider) {
this.scopedServiceProvider = scopedServiceProvider;
}
public string PerformMyTask() {
var scopedDependency = scopedServiceProvider.Get();
// do something with scopedDependency to verify we get instances
// appropriate for the current scope
}
}
在我的启动课程中:
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton<ISingletonService, SingletonService>();
services.AddScoped<IScopedService, ScopedService>();
services.AddTransient<IProvider<IScopedService>, Provider<IScopedService>>();
// other bindings here
}
不幸的是,这并没有按照我想要的方式工作,因为 IServiceProvider 实例的范围似乎也限于当前的 HTTP 请求,并且在处理不同请求期间我从我的提供者那里获得了完全相同的 ScopedDependency 实例:(
有任何提示我该如何解决这个问题吗?
是否有比 ServiceProvider 更高级别的对象,大致绑定到应用程序生命周期(而不是当前请求),创建请求范围对象(或 ServiceProvider 本身)的实例,我可以将其注入到我的 Provider 对象而不是 ServiceProvider 中?例如,在 Java 中,如果我使用 google Guice 作为 DI 框架,则会有一个 Injector 对象,通常在应用程序启动时创建,该对象保存所有类型绑定并具有一个方法
<T> T getInstance(Class<T> type);
它检查当前作用域是什么并返回相应的实例。
edit:
我认为一种可能的方法是每次在 Proivder.Get() 方法中获取对 ServiceProvider 实例的新引用,而不是注入构造函数并存储为实例变量。这样,我的组件仍然不会受到对特定于框架的 IServiceProvider 的引用的污染,因为在它们通过抽象 IProvider 接口访问的 Provider 实现中,它将对它们隐藏起来。然而,我无法在网上找到是否可以从我的 Provider 类获取这样的引用以及如何执行此操作。任何朝这个方向的指示将不胜感激:)
Thanks!