.NET Core HealthCheck — добавление HealthCheck с внедрением зависимостей и параметров

У меня есть разные классы, которые наследуют базовый класс. Базовый класс реализует интерфейс IHealthCheck. У каждого класса есть конструктор, которому нужен регистратор и параметры в соответствии с классом. Например :

public ConnectionHealthCheck(ILogger logger, string address)
        : base(logger)
    {
         Address = address;
    }

У меня есть файл appSettings.json, который позволяет настроить несколько диагностических функций в моей службе проверки работоспособности.

Я получаю список диагностики в своем App.xaml.cs и пытаюсь добавить их в список HealthCheck.

Проблема в том, что я не могу сделать инъекцию зависимости с параметрами рядом с ней, и я не знаю, как лучше всего это сделать...

Вот некоторые части моего кода.

Метод OnStartup:

protected override void OnStartup(StartupEventArgs e)
    {
        var a = Assembly.GetExecutingAssembly();
        using var stream = a.GetManifestResourceStream("appsettings.json");

        Configuration = new ConfigurationBuilder()
            .AddJsonStream(stream)
            .Build();

        var host = new HostBuilder()
            .ConfigureHostConfiguration(c => c.AddConfiguration(Configuration))
                .ConfigureServices(ConfigureServices)
                .ConfigureLogging(ConfigureLogging)
                .Build();
       [...] }

Метод configureService:

private void ConfigureServices(IServiceCollection serviceCollection)
    {
        // create and add the healthCheck for each diag in the appSettings file
        List<DiagnosticConfigItem> diagnostics = Configuration.GetSection("AppSettings:Diagnostics").Get<List<DiagnosticConfigItem>>();
        diagnostics.ForEach(x => CreateHealthCheck(serviceCollection, x)); 
        [...] }

И метод CreateHealthCheck, где проблема:

private void CreateHealthCheck(IServiceCollection serviceCollection, DiagnosticConfigItem configItem)
    {
        EnumDiagType type;

        try
        {
            type = (EnumDiagType)Enum.Parse(typeof(EnumDiagType), configItem.Type, true);
        }
        catch (Exception)
        {
            throw new Exception("Diagnostic type not supported");
        }

        switch (type)
        {
            case EnumDiagType.Connection:
                serviceCollection.AddHealthChecks().AddCheck(nameof(ConnectionHealthCheck), new ConnectionHealthCheck(???, configItem.Value));
                break;
            case EnumDiagType.Other:
                [...] }

Как видите, я не могу создать экземпляр класса ConnectionHealthCheck, потому что не могу получить доступ к объекту ILogger...

Итак, как я могу это сделать? Я думаю о разных решениях, но у меня нет ответа или способа сделать это

  • Создайте службу HealthCheck не в App.xaml.cs, а после ? (В модели представления, например, где у меня есть доступ к serviceCollection и регистратору)

  • Найдите способ заставить регистратор использовать его в методе CreateHealthCheck?

  • Сделайте что-нибудь подобное, но я не знаю, когда смогу передать параметры

    serviceCollection.AddHealthChecks().AddCheck<ConnectionHealthCheck>(nameof(ConnectionHealthCheck));


person Elsassmania    schedule 26.06.2020    source источник


Ответы (2)


Вы можете использовать HealthCheckRegistration для регистрации вашего класса (он должен реализовать IHealthCheck), у него есть конструкторы, принимающие делегата Func<IServiceProvider,IHealthCheck>, который позволяет вам использовать IServiceProvider для разрешения необходимых параметров для создания экземпляра вашего класса проверки работоспособности. Что-то вроде этого:

public static class ConnectionHealthCheckBuilderExtensions
{
    const string DefaultName = "example_health_check";

    public static IHealthChecksBuilder AddConnectionHealthCheck(
        this IHealthChecksBuilder builder,
        string name = default,
        DiagnosticConfigItem configItem,
        HealthStatus? failureStatus = default,
        IEnumerable<string> tags = default)
    {
        return builder.Add(new HealthCheckRegistration(
            name ?? DefaultName,
            sp => new ConnectionHealthCheck(sp.GetRequiredService<ISomeService>(), configItem.Value),
            failureStatus,
            tags));
    }
}

См. эту часть документации для получения более подробной информации.

person Guru Stron    schedule 26.06.2020
comment
Кажется, это хорошее решение, но у меня возникла проблема, когда я пытаюсь запустить HealthCheck. Регистратор в Builder не может быть разрешен, и у меня есть исключение: служба типа «Microsoft.Extensions.Logging.ILogger» не зарегистрирована. У вас есть идея, почему? - person Elsassmania; 30.06.2020
comment
@Elsassmania, вы пытаетесь внедрить/разрешить неуниверсальное ILogger, которое не поддерживается, вы должны ввести/разрешить ILogger<SomeClass>, в данном случае ILogger<ConnectionHealthCheck> (на самом деле, поскольку вы обрабатываете это разрешение вручную, вы все еще можете иметь ILogger в центре проверки работоспособности, но должен разрешить общий: sp.GetRequiredService<ILogger<ConnectionHealthCheck>>()) - person Guru Stron; 30.06.2020
comment
Упс! Вы правы, я забыл ввести Logger. Теперь все работает, спасибо за помощь! - person Elsassmania; 30.06.2020

Встроенный DI .NET Core может внедрять компоненты на уровне конструктора. Поэтому используйте следующий способ, который я использую в своих основных проектах ASP.NET.

public class Startup
{
    public Startup(IWebHostEnvironment environment, IConfiguration configuration, ILoggerFactory loggerFactory)
    {
        Environment = environment;
        Configuration = configuration;
        LoggerFactory = loggerFactory;
    }

    public IConfiguration Configuration { get; }
    public ILoggerFactory LoggerFactory { get; }
    public IWebHostEnvironment Environment { get; }
    
    private void ConfigureServices(IServiceCollection serviceCollection)
    {
        List<DiagnosticConfigItem> diagnostics = Configuration.GetSection("AppSettings:Diagnostics").Get<List<DiagnosticConfigItem>>();
        diagnostics.ForEach(x => CreateHealthCheck(serviceCollection, x, LoggerFactory)); 
    }
    private void CreateHealthCheck(IServiceCollection serviceCollection, DiagnosticConfigItem configItem)
    {
        // Create a ILogger<T> based on your Type by
        loggerFactory.CreateLogger<MessagingServices>())
    }
}
    

Это может быть грубо, но надеюсь, что это поможет.

person Sathish Guru V    schedule 26.06.2020