mardi 21 juin 2022

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".

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.

What I want is something like (but will not work):

    public static ServiceProvider AddDataHealthChecks(this ServiceProvider serviceProvider, IServiceCollection services)
{
    using IServiceScope scope = serviceProvider.CreateScope();
    IEnumerable<IDataCheck>? dataServices = serviceProvider.GetServices<IDataCheck>();
    foreach (IDataCheck? s in dataServices)
    {
        services
            .AddHealthChecks()
            .AddTypeActivatedCheck<DataQualityHealthCheck>(nameof(s),
                failureStatus: HealthStatus.Degraded,
                tags: new[] { "data" },
                args: new object[] { s });
    }
    return serviceProvider;
}

(so that based on the name it can lookup the healthcheck class and then call the RunCheckAsync on this specific one) (so that in the UI under the foldout "data" there will these seperate rows of results by the name s.name).

But this will not work since on the moment of calling this, the services are not there yet and service provider is not there yet. And i think... doing this via reflection on all IData classes in all assemblies found will result in the same failure.

So probably this will have to go after building the service collection and then via reflection and then dynamically adding it i think ?





Aucun commentaire:

Enregistrer un commentaire