如何在C#/ ASP中的单例中使用作用域依赖项

我是来自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 get(); } 

其中有助于解决范围问题:只要某个类型T的绑定是注册,我们就可以注入一个自动生成的Provider 实例而不是T,然后在需要时获取T的实例:a自动生成的Provider确保我们获得适合当前作用域的实例(无论此作用域是什么:HTTP请求,HTTP会话或其他自定义作用域)。 ASP.NET核心内置的标准DI框架没有这样的东西,但我认为在C#中应该很容易实现,因为C#generics不像java那样糟糕( https://docs.oracle.com/ javase / tutorial / java / generics / erasure.html )。 所以我创建了以下类:

 public class Provider: IProvider { private readonly IServiceProvider serviceProvider; public Provider(IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; } public T IProvider.Get() { return serviceProvider.GetService(); } } 

我决定以下列方式使用它:

 public class SingletonService : ISingletonService { private readonly IProvider scopedServiceProvider; public SingletonService(IProvider 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 } } 

在我的Startup课程中:

 public void ConfigureServices(IServiceCollection services) { services.AddSingleton(); services.AddScoped(); services.AddTransient<IProvider, Provider>(); // other bindings here } 

不幸的是,这不是我想要的方式,因为IServiceProvider实例似乎也限定为当前的HTTP请求,并且在处理不同请求期间,我从我的提供者获得完全相同的ScopedDependency实例:(

任何提示如何解决这个问题? 是否有比ServiceProvider更高级别的对象,大致绑定到应用程序生命周期(而不是当前请求),它创建了我可以注入到我的Provider对象而不是ServiceProvider的请求范围对象(或ServiceProvider本身)的实例? 例如在Java中,如果我使用google Guice作为DI框架,则会有一个Injector对象,通常在应用程序启动时创建,该应用程序包含所有类型绑定并具有方法

  T getInstance(Class type); 

检查当前范围是什么并返回相应的实例。

编辑:

我认为一种可行的方法是每次在Proivder .Get()方法中获取对ServiceProvider实例的新引用,而不是在构造函数中注入并存储为实例var。 这样,我的组件仍然不会被对框架特定的IServiceProvider的引用所污染,因为它们在它们通过抽象IProvider 接口访问的Provider 的实现中将被隐藏。 但是我无法在网上找到是否可以从我的Provider类获得这样的引用以及如何执行此操作。 这个方向的任何指针将不胜感激:)

谢谢!

好的,找到了:

 public class Provider : IProvider { IHttpContextAccessor contextAccessor; public Provider(IHttpContextAccessor contextAccessor) { this.contextAccessor = contextAccessor; } T IProvider.Get() { return contextAccessor.HttpContext.RequestServices.GetService(); } } 

在初创公司:

  public void ConfigureServices(IServiceCollection services) { services.TryAddSingleton(); services.AddSingleton(); services.AddScoped(); services.AddTransient, Provider>(); // other bindings } 

🙂

有关使用和注册HttpContextAccessor的更多详细信息,请参阅https://github.com/aspnet/Hosting/issues/793