Back in .net core 2, I had created a hosted service with a custom property like:
public class MyService : BackgroundService
{
public bool IsRunning {get;set;}
...
That I could setup in startup.cs like:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHostedService,HostedServices.MyService>();
...
And then I could reference it elsewhere in a razor page like:
public class IndexModel : PageModel
{
private readonly IHostedService _mySrv;
public IndexModel(IHostedService mySrv) => _mySrv = mySrv;
[BindProperty]
public bool IsRunning { get; set; }
public void OnGet() => IsRunning = ((HostedServices.MyService)_mySrv).IsRunning;
}
Now that I've upgraded to .net core 3, my startup has changed to:
services.AddHostedService<HostedServices.MyService>();
But my DI reference in IndexModel doesn't get me my MyService anymore, it gives me an object of type GenericWebHostService instead, that I can't figure out how to get my custom MyService from. Changing 'IHostedService' to 'MyService' in IndexModel doesn't work either, i get a 'Unable to resolve service' error.
How do I get an instance of MyService back from dependency injection?
In ASP.NET Core, background tasks can be implemented as hosted services. A hosted service is a class with background task logic that implements the IHostedService interface. This article provides three hosted service examples: Background task that runs on a timer. Hosted service that activates a scoped service.
When you register implementations of IHostedService using any of the AddHostedService extension methods - the service is registered as a singleton. There may be scenarios where you'd like to rely on a scoped service. For more information, see Dependency injection in .
In 2.2, the setup you had worked mostly by chance. Whenever you register multiple implementations against a service, the last-registered is the one that "wins". For example, take the following code:
services.AddSingleton<IHostedService, HostedService1>();
services.AddSingleton<IHostedService, HostedService2>();
// ...
public IndexModel(IHostedServie hostedService) { }
The implementation of IHostedService
that gets injected into IndexModel
is HostedService2
; the last registered. If IndexModel
were to be updated to take an IEnumerable<IHostedService>
, it would get both implementations, in order of registration:
public IndexModel(IEnumerable<IHostedService> hostedServices) { }
When I said "by chance", I meant that in your example, only HostedServices.MyService
gets registered, so it's also the last-registered and therefore it "wins".
In 3.0, when using the Generic Host, an implementation of IHostedService
, GenericWebHostService
, handles processing web requests. This gives you a problem, because the GenericWebHostService
is registered after HostedServices.MyService
. I hope it's clear by now that this is the reason why the IHostedService
you request in IndexModel
is not what you expected.
In terms of a solution, I suggest performing two registrations:
services.AddSingleton<HostedServices.MyService>();
services.AddHostedService(sp => sp.GetRequiredService<HostedServices.MyService>());
Then, update your IndexModel
to require your specific implementation:
public IndexModel(HostedServices.MyService myService) { }
This allows you to target your specific implementation of IHostedService
. It's registered twice, against two different service types, but only one instance gets created.
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