When I'm registering factory for IPersonProvider like this:
services.AddScoped<IPersonProvider, PersonProvider>();
services.AddSingleton<Func<IPersonProvider>>(sp => () => sp.GetService<IPersonProvider>());
I'm getting error:
InvalidOperationException: Cannot resolve scoped service 'DependencyApp.Provider.IPersonProvider' from root provider.
I'm aware that I can't resolve Singleton object with Scoped dependencies, but as I understand my factory doesn't have any Scoped dependencies - in fact it doesn't have any dependencies. It just creates objects when I ask to like this:
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";
}
}
Why am I getting this error then? How to solve the problem? I believe registering factory as Singleton that can live as long as the whole application shouldn't have any problem creating scoped objects - eventually those created objects aren't really dependencies of the singleton.
The reason why you are having this issue is due to the instance of IServiceProvider being used. When you register a service as singleton, then the root IServiceProvider is passed to the factory method.
So when you have:
services.AddSingleton<Func<IPersonProvider>>(sp => () => sp.GetService<IPersonProvider>());
It means that sp must be compatible with the singleton lifetime, which is only the root service provider.
To illustrate what I mean.
using (var scopedServiceProvider = sp.CreateScope())
{
scopedServiceProvider.GetService<IPersonProvider>(); // valid
sp.GetService<IPersonProvider>(); // not valid
}
However, when your factory method is of transient lifetime, the sp passed in no longer uses the root service provider and instead uses a derived one where the restriction of instantiating scoped services does not apply.
To reiterate the problem, the sp that you're using is not able to create scoped services, so it's not a matter of the service being returned being a Func, but instead the fact that the provider is the root one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With