My .net core app needs to crawl data in a specified time interval. I have chosen to implement IHostedService
to run it in parallel with API. The hosted service needs some services injected. I register them in startup.cs
, but I get an error:
System.InvalidOperationException: 'Cannot consume scoped service 'IXService' from singleton 'Microsoft.AspNetCore.Hosting.Internal.HostedServiceExecutor'.'
My startup.cs:
services.AddScoped<IXService, XService>();
services.AddHostedService<MyHostedService>();
I had a similar problem yet with DbContext, I solved it with https://stackoverflow.com/a/48368934/8475133, but this time I need dependency injection going through deeper layers and dealing with IServiceScopeFactory in each doesn't seem to be an elegant solution.
The reason you're not allowed to do this is because MyHostedService has a singleton lifetime, which is a longer lifetime than scoped. The basic assumption here is that a service that is registered as scoped should not be kept alive indefinitely, this could easily happen if a singleton service keeps a reference to a scoped service.
I think the solution you're looking for is to inject IServiceProvider into MyHostedService, use it to create a new scope and new XService instance whenever you need it.
That is, replace
_xService.Foo();
with
using(var scope = _serviceProvider.CreateScope()) {
var xService = scope.ServiceProvider.GetService<IXService>();
xService.Foo();
}
An alternative, of course, would be to simply register XService as a singleton, by just replacing the call to AddScoped with AddSingleton, but I would not recommend it.
Edit: I must admit to not reading your link before posting my response. However, I still think this is the most elegant solution.