Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.net core dependency injection to hosted service [duplicate]

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.

like image 410
Michal Rosenbaum Avatar asked Aug 25 '18 19:08

Michal Rosenbaum


People also ask

What is difference between Addtransient and AddScoped and AddSingleton?

Singleton is a single instance for the lifetime of the application domain. Scoped is a single instance for the duration of the scoped request, which means per HTTP request in ASP.NET. Transient is a single instance per code request.

Should I use transient or scoped?

Use Transient lifetime for the lightweight service with little or no state. Scoped services service is the better option when you want to maintain state within a request. Singletons are created only once and not destroyed until the end of the Application. Any memory leaks in these services will build up over time.

Is IHostedService a singleton?

When you register implementations of IHostedService using any of the AddHostedService extension methods - the service is registered as a singleton.


1 Answers

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.

like image 168
Håkon Kaurel Avatar answered Oct 05 '22 02:10

Håkon Kaurel