How to inject dependencies inside an ASP.NET Core Health Check
Short Answer
How to inject dependencies inside an ASP.NET Core Health Check.
If we register our services in a correct order, then SomeDependency
will be available for injection into the SomeHealthCheck
constructor, and SomeHealthCheck
will run as part of the health check feature.
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks();
services.AddSingleton<SomeDependency>();
// register the custom health check
// after AddHealthChecks and after SomeDependency
services.AddSingleton<IHealthCheck, SomeHealthCheck>();
}
More Details
A comment in the Health Check samples states that:
All IHealthCheck services will be available to the health check service and middleware. We recommend registering all health checks as Singleton services.
Full Sample
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
public class SomeDependency
{
public string GetMessage() => "Hello from SomeDependency";
}
public class SomeHealthCheck : IHealthCheck
{
public string Name => nameof(SomeHealthCheck);
private readonly SomeDependency someDependency;
public SomeHealthCheck(SomeDependency someDependency)
{
this.someDependency = someDependency;
}
public Task<HealthCheckResult> CheckHealthAsync(
CancellationToken cancellationToken = default(CancellationToken))
{
var message = this.someDependency.GetMessage();
var result = new HealthCheckResult(HealthCheckStatus.Failed, null, null, null);
return Task.FromResult(result);
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks();
services.AddSingleton<SomeDependency>();
services.AddSingleton<IHealthCheck, SomeHealthCheck>();
}
public void Configure(IApplicationBuilder app)
{
app.UseHealthChecks("/healthz");
app.Run(async (context) => await context.Response.WriteAsync("Hello World!"));
}
}
This sample is also available on GitHub here.
As of .NET Core 3.0, the registration is simpler and boils down to this
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks();
services.AddSingleton<SomeDependency>();
services.AddCheck<SomeHealthCheck>("mycheck");
}
Note that you no longer have the singleton vs transient conflict as you use what the engine needs to use.
The name of the check is mandatory, therefore you have to pick up one.
While the accepted asnwer seems no longer to work.
Dependency injection for health checks in asp.net core works exactly as it works for any other registered service that is added through ServiceProvider
.
This means creating your health check as
public class Foo : IHealthCheck {
private ILogger<Foo> _log;
public Foo(ILogger<Foo> log) {
_log = log; // log is injected through the DI mechanisms
}
}
And registering (using the new 6 style here):
builder.AddHealthChecks().AddHealthCheck<Foo>();
So this also means that you can inject the IServiceProvider
itself and utilise it internally should the need for getting further required services or werid use cases be there.
I am very curious why this is not explicitly stated in the documentation and there are no examples for this, as it is not "obvious". But it clearly follows the classical pattern of everything in the asp.net core land.
In addition to Shaun's answer: there is an open pull-request which will allow to inject services with any lifetime (transient and scoped) into health checks. This will probably land in the 2.2 release.
When you can use transient and scoped services in health checks, you should register them using a transient lifestyle.