ASP.NET Core - DI, rejestracja Factory

0

Co chcę osiągnąć?

Zarejestrować we wbudowanym kontenerze ASP.NET Core factory do tworzenia obiektów IPersonProvider.

Jak próbuję to zrobić?

Rejestruję IPersonProvider w kontenerze oraz fabrykę Func<IPersonProvider> (jak poniżej)

Rejestracja:

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

Wywołanie:

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";
    }
}

Jaki problem?

Ustawienie life cycli. Wydaje mi się, że sama factory powinna być Singleton (współdzielona przez aplikację), gdyż jest jedynie odpowiedzialna za utworzenie obiektu IPersonProvider, gdy jest potrzebny. IPersonProvider z kolei nie nadaje się na Singleton, ale jak najbardziej może być współdzielona per web request (Scoped). Problem, że w przypadku rejestracji Singleton-Scoped dostaję błąd:

InvalidOperationException: Cannot resolve scoped service 'DependencyApp.Provider.IPersonProvider' from root provider.

O dziwo, gdy zmienię lifecycle dla IPersonProvider z AddScoped na AddTransient to działa. Aczkolwiek dużo bardziej preferowałbym Scoped, gdyż utworzenie IPersonProvider jest dość kosztowne, a jak najbardziej może być współdzielone per request.

Dziękuję z góry za jakieś sugestie dlaczego tak to działa.

0

If we think back to how our creation counts worked. When we have a scoped instance, each time we load the page, a new instance of our ChildService is created and inserted in the parent service. Whereas when we do a singleton, it keeps the exact same instance (Including the same child services). When we make the parent service a singleton, that means that the child service is unable to be created per page load. ASP.net Core is essentially stopping us from falling in this trap of thinking that a child service would be created per page request, when in reality if the parent is a singleton it’s unable to be done. This is why the exception is thrown.

What’s the fix? Well either the parent needs to be scoped or transient scope. Or the child needs to be a singleton itself. The other option is to use a service locator pattern but this is not really recommended. Typically when you make a class/interface singleton, it’s done for a very good reason. If you don’t have a reason, make it transient

https://dotnetcoretutorials.com/2018/03/20/cannot-consume-scoped-service-from-singleton-a-lesson-in-asp-net-core-di-scopes/.

0

@szydlak, to się zgadza, ale kontekst mojego problemu jest raczej inny. Ten co podlinkowałeś to sytuacja, gdy mam klasę A, która ma dependency klasę B i w rejestracji A jest Singleton, B scoped - singleton nie może mieć dependency scoped. W moim przypadku chcę wstrzykiwać factory singleton, który tworzy obiekty scoped. Takżę tutaj samo factory nie ma żadnej zależności scoped. Tak to przynajmniej rozumiem.

1

Pytanie po co Ci ta fabryka? Z tego, co widzę to ona tylko tworzy instancję IPersonProvider. Bez żadnych warunków. Potrzebna Ci jest ta fabryka, czy wystarczy sama rejestracja PersonProvider?

1 użytkowników online, w tym zalogowanych: 0, gości: 1