Search code examples
c#asp.net-core.net-coredependency-injectionhealth-check

IHealthChecksBuilder.AddTypeActivatedCheck with access to IServiceProvider


Is there a way to use IHealthChecksBuilder.AddTypeActivatedCheck<T>() with a delegate function of Action<IServiceProvider>? I need to be able to access the service container and resolve a dependency in order to build a check. I see no way of doing this with that method. Of course I can use AddScoped<IHealthCheck>(Action<IServiceProvider> action) method signature to do this, but now I see no way of setting metadata information for the health check (name, tags, failure condition, etc.).


Solution

  • I need to be able to access the service container and resolve a dependency in order to build a check.

    Usually you don't need to do that, since the AddTypeActivatedCheck can resolve all the needed parameters and pass it to the health check ctor (i.e. move the construction logic there). From the remarks in the docs:

    This method will use ActivatorUtilities.CreateInstance<T>(IServiceProvider, Object[]) to create the health check instance when needed. Additional arguments can be provided to the constructor via args.

    i.e. for the following check with 3 parameters, 2 of which will be resolved from DI:

    public class SampleHealthCheck(
        SomeService serv, 
        int i, 
        SomeService2 someService2) : IHealthCheck
    {
        public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken ct = default) =>
            Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
    }
    

    You can use the following registration:

    builder.Services.AddSingleton<SomeService>();
    builder.Services.AddSingleton<SomeService2>();
    builder.Services.AddHealthChecks()
        .AddTypeActivatedCheck<SampleHealthCheck>("sample", 42);
    

    But if this is some rare case when you have some kind of factory logic (and you don't want to move it to the health check implementation) or something else blocking from just injecting all the needed dependencies via healthckeck ctor then you can use HealthCheckRegistration class directly:

    builder.Services.AddHealthChecks()
        .Add(new HealthCheckRegistration(
            "sample", 
            sp => new SampleHealthCheck(sp.GetRequiredService<SomeService>(), 42, sp.GetRequiredService<SomeService2>()),
            failureStatus: HealthStatus.Unhealthy,
            tags: null
            ));
    

    See the Distribute a health check library section of the docs.