I am trying to add a Background Timer in ASP.NET Core 3.0, which periodically executes a task. Google led me to this, where I implemented the 'Timed background tasks'. However, I'm stuck in resolving the HostedService in the controller. I need a specific instance of TimedHealthCheckService so I can call another public function called 'GetAvailableODataUrl()'.
In the startup.cs
I use the following code:
services.AddHostedService<TimedHealthCheckService>();
The TimedHealthCheckService obviously implements IHostedService:
public class TimedHealthCheckService : IHostedService, IDisposable
In my controller, I have the following constructor:
public HealthCheckController(ILogger<HealthCheckController> logger, IHostedService hostedService) { this.logger = logger; this.timedHealthCheckService = hostedService as TimedHealthCheckService; }
However, when I start my WebAPI, the timedHealthCheckService
is always null. It seems another IHostedService gets injected into the constructor. By checking hostedService, it is actually an object of type GenericWebHostService.
If I change the controller's constructor to:
public HealthCheckController(ILogger<HealthCheckController> logger, TimedHealthCheckService hostedService)
I am getting the following error:
Unable to resolve service for type 'HealthCheck.Web.TimedHealthCheckService' while attempting to activate 'HealthCheck.Web.Controllers.HealthCheckController'.
I also tried services.AddSingleton<IHostedService, TimedHealthCheckService>();
with the same result.
You need to pass controller namespace (using constructor) so every controller should be same namespace and. All controllers need single parameterized construction which accept ILogger object only. Without that it will throw MissingMethodException .
ASP.NET Core injects objects of dependency classes through constructor or method by using built-in IoC container. The built-in container is represented by IServiceProvider implementation that supports constructor injection by default.
You can take advantage of the ServiceFilter attribute to inject dependencies in your controller or your controller's action methods.
Try these two lines in startup.cs:
services.AddSingleton<TimedHealthCheckService>(); services.AddHostedService<TimedHealthCheckService>(provider => provider.GetService<TimedHealthCheckService>());
The first line above tells the service provider to create a singleton and give it to anyone who wants a TimedHealthCheckService
, like your controller's constructor. However, the service provider is unaware that the singleton is actually an IHostedService
and that you want it to call StartAsync()
.
The second line tells the service provider that you want to add a hosted service, so it'll call StartAsync()
when the application starts running. AddHostedService
accepts a Func<IServiceProvider,THostedService>
callback. The callback we provide fetches the singleton TimedHealthCheckService
from the service provider and returns it back to the service provider as an IHostedService
. The service provider then calls its StartAsync()
function.
And in your controller:
public HealthCheckController(ILogger<HealthCheckController> logger, TimedHealthCheckService hostedService)
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