首页 > 解决方案 > 如何在 ASP.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";
    }
}

为什么我会收到此错误?如何解决问题?我相信将工厂注册为单例,只要整个应用程序在创建作用域对象时没有任何问题——最终这些创建的对象并不是单例的真正依赖项。

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

解决方案


您遇到此问题的原因是由于使用的实例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您正在使用的 无法创建范围服务,因此返回的服务不是 a 的问题Func,而是提供者是根的事实。


推荐阅读