如何在ASP.NET Core中注册单例工厂解析范围对象?

时间:2019-05-13 21:35:18

标签: c# asp.net-core dependency-injection .net-core

当我像这样为IPersonProvider注册工厂时:

services.AddScoped<IPersonProvider, PersonProvider>();
services.AddSingleton<Func<IPersonProvider>>(sp => () => sp.GetService<IPersonProvider>());

我遇到错误:

  

InvalidOperationException:无法从根提供者解析作用域服务'DependencyApp.Provider.IPersonProvider'。

我知道我无法解析具有Scoped依赖项的Singleton对象,但是据我了解,我的工厂没有任何Scoped依赖项-实际上它没有任何依赖项。当我要求这样时,它只是创建对象:

public class HomeController : Controller
{
    private readonly Func<IPersonProvider> _factory;

    public HomeController(Func<IPersonProvider> factory)
    {
        _factory = factory;
    }

    [Route("/")]
    public string Calculate()
    {
        var personProvider = _factory();
        //.
        //.
        //.

        return "test";
    }
}

那我为什么会收到此错误?如何解决问题?我相信将工厂注册为Singleton可以生存,只要整个应用程序在创建作用域对象时没有任何问题-最终那些创建的对象实际上并不是Singleton的依赖项。

2 个答案:

答案 0 :(得分:1)

出现此问题的原因是由于使用了IServiceProvider实例。将服务注册为单例时,根IServiceProvider会传递给工厂方法。

因此,当您拥有:

services.AddSingleton<Func<IPersonProvider>>(sp => () => sp.GetService<IPersonProvider>());

这意味着sp必须与单例生存期兼容,后者仅仅是根服务提供者。

说明我的意思。

using (var scopedServiceProvider = sp.CreateScope())
{
    scopedServiceProvider.GetService<IPersonProvider>(); // valid

    sp.GetService<IPersonProvider>(); // not valid
}

但是,当您的工厂方法具有临时生存期时,传入的sp将不再使用根服务提供者,而是使用派生的提供者,其中不实例化作用域服务的限制。

要重申此问题,您正在使用的sp无法创建范围服务,因此返回的服务不是Func的问题,而是以下事实:提供者是根源。

答案 1 :(得分:0)

我已经按照其正常工作完成了

 services.AddSingleton<ITokenManager, TokenManger>();
 services.AddScoped<ITokenProvider, TokenProvider>();

public class TokenProvider : ITokenProvider
{
    private readonly ITokenManager _tokenManager;
    public TokenProvider(ITokenManager tokenManager)
    {
        _tokenManager = tokenManager;
    }
}