IServiceProvider 以单例方式处理

问题描述 投票:0回答:1

在 ASP.NET core 中,我有一个单例服务,它使用范围服务,它本身需要实例化新服务本身。

public class Startup
{
   public void ConfigureServices(IServiceCollection services)
   {
      services.AddSingleton<MySingleton>();
      services.AddScoped<MyScoped>();
   }
}

public class MySingleton
{
   private IServiceScopeFactory _serviceScopeFactory;
   public MySingleton(IServiceScopeFactory serviceScopeFactory)
   {
      _serviceScopeFactory = serviceScopeFactory;
   }

   public async Task Foo()
   {
      AsyncServiceScope serviceScope = _serviceScopeFactory.CreateAsyncScope();
      await serviceScope.ServiceProvider.GetService<MyScoped>().Bar();
      await serviceScope.DisposeAsync();
   }
}

public class MyScoped
{
   private IServiceScopeFactory _serviceScopeFactory;
   public MyScoped(IServiceScopeFactory serviceScopeFactory)
   {
      _serviceScopeFactory = serviceScopeFactory;
   }

   public async Task Bar()
   {
      AsyncServiceScope serviceScope = _serviceScopeFactory.CreateAsyncScope();
      SomeType s = await (SomeType)ActivatorUtilities.CreateInstance(serviceScope .ServiceProvider, someType);
      s.DoSomething();
      await serviceScope.DisposeAsync();
   }   
}

一段时间后,当调用

await serviceScope.ServiceProvider.GetService<MyScoped>().Bar();
时,我收到错误:

您无法访问已处置的对象。 IServiceProvider!.

为什么我会收到此错误?解决此错误的最佳方法是什么? 我已经测试过注入

IServiceProvider
IServiceProviderFactory
IServiceScopeFactory

根据我的理解,

IServiceScopeFactory
应该阻止访问已经处置的ServiceProvider。

c# asp.net-core dependency-injection
1个回答
0
投票

简化你的例子,检查我是否理解。

假设您想使用单例,因为(比如说)有大量数据被初始化一次。然后剩下的逻辑需要划分范围。

因此,您创建了一个试图采用作用域依赖项的单例:

public interface IBarScoped
{
    void Bar();
}

public interface IFooSingleton
{
    void Foo();
}
public class FooSingleton
{
    private readonly IDictionary<string, string> _singletonHugeAmountOfData;
    private readonly IBarScoped _scoped;

    public FooSingleton(IBarScoped scoped)
    {
        // 1. Great, we can set up our singleton data.
        _singletonHugeAmountOfData = CreateLotsOfData();

        // 2. But... This doesn't work.
        // When the Scoped dependency changes, how will your DI re-generate your singleton?
        // Answer is: it can't.
    }
}

这没有道理。您是在要求每次作用域依赖项发生变化时都会重新构建您的单例吗?一旦执行完成,范围内的所有内容都会被处理。

但是你不希望整个事情都被限定范围,因为你的字典初始化很大。

所以相反:翻转你的想法,让你的单例成为大部分作用域,对于任何依赖于其他作用域依赖项的东西。然后将真正独立部分提取到不同的单例中,这依赖于任何范围。

Foo
不再是单例。现在已确定范围。一切正常。

public interface IBarScoped
{
    void Bar();
}

public interface IFooScoped
{
    void Foo();
}

public interface IDataSingleton
{
    IDictionary<string, string> SingletonHugeData();
}
public class FooScoped
{
    private readonly IDataSingleton _singletonData;
    private readonly IBarScoped _scoped;

    public FooScoped(IDataSingleton singletonData, IBarScoped scoped)
    {
        // 1. Great, we can set up our singleton data.
        _singletonData = singletonData;

        // 2. And also, Foo can now be declared as scoped,
        // which means we can take an IBarScoped dep as well.
        _scoped = scoped;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.