Как зарегистрировать одноуровневое фабричное разрешение объектов в ASP.NET Core?

Когда я регистрирую фабрику для IPersonProvider, вот так:

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

Я получаю ошибку:

InvalidOperationException: Невозможно разрешить определенную службу DependencyApp.Provider.IPersonProvider из корневого поставщика.

Я знаю, что не могу разрешить объект Singleton с зависимостями Scoped, но, как я понимаю, у моей фабрики нет никаких зависимостей 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 ответа


Причиной возникновения этой проблемы является использование экземпляра IServiceProvider . Когда вы регистрируете сервис как singleton, то корневой 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 , а в том, что провайдер является корневым.


Я сделал после его работы нормально:

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

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