Search code examples
c#asp.net-coredependency-injectionreflectionhealth-check

Dynamically create healthchecks based on all services that have a certain interface


I have a long set of services that check data, and all under the interface "IDataCheck".

IDataChecks is an empty interface with one method "runCheckAsync"

In a commandline app I do:

IEnumerable<IDataCheck>? services = _serviceProvider.GetServices<IDataCheck>();
foreach (IDataCheck? s in services)
{
    DataCheckResult result = await s.RunCheckAsync();
    // all kinds of stuff with the result such as proposing to autofix
}

I now want to also present the results of these checks in asp.net core healtchecks using also the healthcheck ui, ref:

I do not want to create manually a healthcheck per data check because otherwise the usefulness of having an interface is gone

I also do not want to create one healthcheck only otherwise it will produce a long list of results all in one text only column in the ui since it does not support any formatting.


Solution


  • Solved this , with help from the comment from Guru, on the line before "WebApplication app = builder.Build();" to call:

    public static IServiceCollection AddDataHealthChecks(this IServiceCollection services)
    {
        List<string> dataCheckClassList = new List<string>();
        IEnumerable<ServiceDescriptor>? dataServices = services.Where(x => x.ServiceType == typeof(IDataCheck));        
        foreach (ServiceDescriptor s in dataServices)
        {
            var fullName = s.ImplementationType?.FullName;
            if (fullName is not null)
            {
                dataCheckClassList.Add(fullName);
            }
        }
        foreach(string fullName in dataCheckClassList)
        {
            services
                    .AddHealthChecks()
                    .AddTypeActivatedCheck<DataQualityHealthCheck>(fullName,
                        failureStatus: HealthStatus.Degraded,
                        tags: new[] { "data" },
                        args: new object[] { fullName });
        }
    
        return services;
    }
    

    and then in the healtcheck itself :

    IDataCheck? service = _serviceProvider
                .GetServices<IDataCheck>().FirstOrDefault(x => (x.ToString() == _dataCheckServiceName));
    if (service is not null)
    {
       DataCheckResult result = await service.RunCheckAsync();
       // etc
    }