Controlli di integrità in ASP.NET Core

Di Glenn Condron e Juergen Gutsch

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 8 di questo articolo.

ASP.NET Core offre il middleware e le librerie di controlli di integrità per segnalare l'integrità dei componenti dell'infrastruttura delle app.

I controlli di integrità vengono esposti da un'app come endpoint HTTP. Gli endpoint di controllo integrità possono essere configurati per vari scenari di monitoraggio in tempo reale:

  • I probe di integrità possono essere usati dagli agenti di orchestrazione e dai servizi di bilanciamento del carico per controllare lo stato di un'app. Ad esempio, un agente di orchestrazione potrebbe rispondere a controllo di integrità non superato arrestando una distribuzione in sequenza o riavviando un contenitore. Un servizio di bilanciamento del carico potrebbe reagire a un'app non integra trasferendo il traffico dall'istanza con errori a un'istanza integra.
  • È possibile monitorare lo stato di integrità di memoria, disco e altre risorse fisiche del server.
  • I controlli di integrità possono testare le dipendenze di un'app, ad esempio i database e gli endpoint di servizio esterni, per verificare la disponibilità e il normale funzionamento.

I controlli di integrità vengono in genere usati con un servizio di monitoraggio esterno o un agente di orchestrazione del contenitore per controllare lo stato di un'app. Prima di aggiungere i controlli di integrità a un'app, decidere quale sistema di monitoraggio usare. Il sistema di monitoraggio determina quali tipi di controlli di integrità creare e come configurare i relativi endpoint.

Probe di integrità di base

Per molte app, una configurazione del probe di integrità di base, che segnala la disponibilità dell'app per elaborare le richieste (attività), è sufficiente per individuare lo stato dell'app.

La configurazione di base registra i servizi di controllo integrità e chiama il middleware controlli di integrità per rispondere a un endpoint URL con una risposta di integrità. Per impostazione predefinita, non vengono registrati controlli di integrità specifici per testare particolari dipendenze o sottosistemi. L'app viene considerata integra se può rispondere all'URL dell'endpoint di integrità. Il writer di risposta predefinito scrive HealthStatus come risposta in testo non crittografato al client. è HealthStatus HealthStatus.Healthy, HealthStatus.Degradedo HealthStatus.Unhealthy.

Registrare i servizi dei controlli di integrità con AddHealthChecks in Program.cs. Creare un endpoint di controllo dell'integrità chiamando MapHealthChecks.

L'esempio seguente crea un endpoint di controllo integrità in /healthz:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

Docker offre una direttiva HEALTHCHECK predefinita che può essere usata per controllare lo stato di un'app che usa la configurazione dei controlli di integrità di base:

HEALTHCHECK CMD curl --fail http://localhost:5000/healthz || exit

Nell'esempio precedente viene curl usato per effettuare una richiesta HTTP all'endpoint del controllo integrità in /healthz. curl non è incluso nelle immagini del contenitore .NET Linux, ma può essere aggiunto installando il pacchetto necessario nel Dockerfile. I contenitori che usano immagini basate su Alpine Linux possono usare l'oggetto incluso wget al posto di curl.

Creare controlli di integrità

I controlli di integrità vengono creati implementando l'interfaccia IHealthCheck. Il metodo CheckHealthAsync restituisce HealthCheckResult che indica l'integrità come Healthy, Degraded o Unhealthy. Il risultato viene scritto come risposta in testo non crittografato con un codice di stato configurabile. La configurazione è descritta nella sezione Opzioni controllo integrità. HealthCheckResult può anche restituire coppie chiave-valore facoltative.

Nell'esempio seguente viene illustrato il layout di un controllo integrità:

public class SampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

La logica del controllo integrità viene inserita nel CheckHealthAsync metodo . Nell'esempio precedente viene impostata una variabile fittizia, , isHealthysu true. Se il valore di isHealthy è impostato su false, viene restituito lo HealthCheckRegistration.FailureStatus stato .

Se CheckHealthAsync genera un'eccezione durante il controllo, viene restituito un nuovo HealthReportEntry oggetto con il relativo HealthReportEntry.Status set su FailureStatus. Questo stato è definito da AddCheck (vedere la sezione Registrare i servizi di controllo integrità) e include l'eccezione interna che ha causato l'errore di controllo. l'oggetto Description è impostato sul messaggio dell'eccezione.

Registrare i servizi di controllo dell'integrità

Per registrare un servizio di controllo integrità, chiamare AddCheck in Program.cs:

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>("Sample");

L'overload AddCheck illustrato nell'esempio seguente imposta lo stato di errore (HealthStatus) per segnalare quando il controllo di integrità indica un errore. Se lo stato di errore è impostato su null (impostazione predefinita), viene segnalato HealthStatus.Unhealthy. Questo overload è uno scenario utile per gli autori di librerie, in cui lo stato di errore indicato dalla libreria viene applicato dall'app quando si verifica un errore di controllo dell'integrità se l'implementazione del controllo dell'integrità rispetta l'impostazione.

I tag possono essere usati per filtrare i controlli di integrità. I tag sono descritti nella sezione Filtri controlli di integrità.

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" });

AddCheck può anche eseguire una funzione lambda. Nell'esempio seguente il controllo integrità restituisce sempre un risultato integro:

builder.Services.AddHealthChecks()
    .AddCheck("Sample", () => HealthCheckResult.Healthy("A healthy result."));

Chiamare AddTypeActivatedCheck per passare argomenti a un'implementazione del controllo integrità. Nell'esempio seguente un controllo di integrità attivato dal tipo accetta un numero intero e una stringa nel relativo costruttore:

public class SampleHealthCheckWithArgs : IHealthCheck
{
    private readonly int _arg1;
    private readonly string _arg2;

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        // ...

        return Task.FromResult(HealthCheckResult.Healthy("A healthy result."));
    }
}

Per registrare il controllo integrità precedente, chiamare AddTypeActivatedCheck con l'intero e la stringa passati come argomenti:

builder.Services.AddHealthChecks()
    .AddTypeActivatedCheck<SampleHealthCheckWithArgs>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" },
        args: new object[] { 1, "Arg" });

Usare il routing dei controlli di integrità

In Program.cschiamare MapHealthChecks sul generatore di endpoint con l'URL dell'endpoint o il percorso relativo:

app.MapHealthChecks("/healthz");

Richiedi host

Chiamare RequireHost per specificare uno o più host consentiti per l'endpoint di controllo integrità. Gli host devono essere Unicode anziché punycode e possono includere una porta. Se non viene fornita una raccolta, viene accettato qualsiasi host:

app.MapHealthChecks("/healthz")
    .RequireHost("www.contoso.com:5001");

Per limitare la risposta dell'endpoint del controllo integrità solo su una porta specifica, specificare una porta nella chiamata a RequireHost. Questo approccio viene in genere usato in un ambiente contenitore per esporre una porta per i servizi di monitoraggio:

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001");

Avviso

L'API che si basa sull'intestazione Host, ad esempio HttpRequest.Host e RequireHost, è soggetta a potenziali spoofing da parte dei client.

Per evitare lo spoofing di host e porta, usare uno degli approcci seguenti:

Per impedire ai client non autorizzati di eseguire lo spoofing della porta, chiamare RequireAuthorization:

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001")
    .RequireAuthorization();

Per altre informazioni, vedere Corrispondenza host nelle route con RequireHost.

Richiedi autorizzazione

Chiamare RequireAuthorization per eseguire il middleware di autorizzazione nell'endpoint della richiesta di controllo integrità. Un RequireAuthorization overload accetta uno o più criteri di autorizzazione. Se non viene specificato un criterio, vengono usati i criteri di autorizzazione predefiniti:

app.MapHealthChecks("/healthz")
    .RequireAuthorization();

Abilitare richieste tra le origini (CORS)

Anche se l'esecuzione manuale dei controlli di integrità da un browser non è uno scenario comune, il middleware CORS può essere abilitato chiamando RequireCors gli endpoint dei controlli di integrità. L'overload RequireCors accetta un delegato del generatore di criteri CORS (CorsPolicyBuilder) o un nome di criteri. Per altre informazioni, vedere Abilitare le richieste tra le origini (CORS) in ASP.NET Core.

Opzioni dei controlli di integrità

HealthCheckOptions consente di personalizzare il comportamento dei controlli di integrità:

Filtrare i controlli di integrità

Per impostazione predefinita, il middleware controlli di integrità esegue tutti i controlli di integrità registrati. Per eseguire un subset dei controlli di integrità, specificare una funzione che restituisce un valore booleano all'opzione Predicate.

Nell'esempio seguente vengono filtrati i controlli di integrità in modo che solo quelli contrassegnati con l'esecuzione sample :

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("sample")
});

Personalizzare il codice di stato HTTP

Usare ResultStatusCodes per personalizzare il mapping dello stato di integrità dei codici di stato HTTP. Le assegnazioni StatusCodes seguenti sono i valori predefiniti usati dal middleware. Modificare i valori del codice di stato per soddisfare i requisiti:

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResultStatusCodes =
    {
        [HealthStatus.Healthy] = StatusCodes.Status200OK,
        [HealthStatus.Degraded] = StatusCodes.Status200OK,
        [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
    }
});

Eliminare le intestazioni della cache

AllowCachingResponses controlla se il middleware controlli di integrità aggiunge intestazioni HTTP a una risposta probe per impedire la memorizzazione nella cache delle risposte. Se il valore è false (impostazione predefinita), il middleware imposta le intestazioni Cache-Control, Expires e Pragma o ne esegue l'override per impedire la memorizzazione della risposta nella cache. Se il valore è true, il middleware non modifica le intestazioni della cache della risposta:

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    AllowCachingResponses = true
});

Personalizzare l'output

Per personalizzare l'output di un report dei controlli di integrità, impostare la HealthCheckOptions.ResponseWriter proprietà su un delegato che scrive la risposta:

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResponseWriter = WriteResponse
});

Il delegato predefinito scrive una risposta in testo non crittografato minima con il valore di stringa HealthReport.Status. Il delegato personalizzato seguente restituisce una risposta JSON personalizzata usando System.Text.Json:

private static Task WriteResponse(HttpContext context, HealthReport healthReport)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions { Indented = true };

    using var memoryStream = new MemoryStream();
    using (var jsonWriter = new Utf8JsonWriter(memoryStream, options))
    {
        jsonWriter.WriteStartObject();
        jsonWriter.WriteString("status", healthReport.Status.ToString());
        jsonWriter.WriteStartObject("results");

        foreach (var healthReportEntry in healthReport.Entries)
        {
            jsonWriter.WriteStartObject(healthReportEntry.Key);
            jsonWriter.WriteString("status",
                healthReportEntry.Value.Status.ToString());
            jsonWriter.WriteString("description",
                healthReportEntry.Value.Description);
            jsonWriter.WriteStartObject("data");

            foreach (var item in healthReportEntry.Value.Data)
            {
                jsonWriter.WritePropertyName(item.Key);

                JsonSerializer.Serialize(jsonWriter, item.Value,
                    item.Value?.GetType() ?? typeof(object));
            }

            jsonWriter.WriteEndObject();
            jsonWriter.WriteEndObject();
        }

        jsonWriter.WriteEndObject();
        jsonWriter.WriteEndObject();
    }

    return context.Response.WriteAsync(
        Encoding.UTF8.GetString(memoryStream.ToArray()));
}

L'API dei controlli di integrità non fornisce il supporto predefinito per i formati restituiti JSON complessi perché il formato è specifico della scelta del sistema di monitoraggio. Personalizzare la risposta negli esempi precedenti in base alle esigenze. Per altre informazioni sulla serializzazione JSON con System.Text.Json, vedere Come serializzare e deserializzare JSON in .NET.

Probe del database

Un controllo di integrità può specificare una query di database da eseguire come test booleano per indicare se il database sta rispondendo normalmente.

AspNetCore.Diagnostics.HealthChecks, una libreria di controllo dell'integrità per le app core ASP.NET, include un controllo integrità eseguito su un database di SQL Server. AspNetCore.Diagnostics.HealthChecks esegue una query SELECT 1 sul database per confermare che la connessione al database sia integra.

Avviso

Quando si controlla una connessione di database con una query, scegliere una query che viene restituita rapidamente. Dall'approccio alla query possono derivare il sovraccarico del database e il degrado delle prestazioni. Nella maggior parte dei casi, l'esecuzione di una query di test non è necessaria. È sufficiente stabilire una connessione al database. Se invece è necessario eseguire una query, scegliere una semplice query SELECT, ad esempio SELECT 1.

Per usare questo controllo integrità di SQL Server, includere un riferimento al AspNetCore.HealthChecks.SqlServer pacchetto NuGet. Nell'esempio seguente viene registrato il controllo integrità di SQL Server:

var conStr = builder.Configuration.GetConnectionString("DefaultConnection");
if (string.IsNullOrEmpty(conStr))
{
    throw new InvalidOperationException(
                       "Could not find a connection string named 'DefaultConnection'.");
}
builder.Services.AddHealthChecks()
    .AddSqlServer(conStr);

Nota

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Probe DbContext di Entity Framework Core

Il DbContext controllo conferma che l'app può comunicare con il database configurato per un oggetto EF CoreDbContext. Il controllo DbContext è supportato nelle app che:

AddDbContextCheck registra un controllo di integrità per un DbContext. L'oggetto DbContext viene fornito al metodo come TContext. È disponibile un overload per configurare lo stato di errore, i tag e una query di test personalizzata.

Per impostazione predefinita:

  • Il DbContextHealthCheck metodo chiama EF Coreil metodo .CanConnectAsync È possibile determinare l'operazione da eseguire quando si controlla l'integrità usando gli overload del metodo AddDbContextCheck.
  • Il nome del controllo di integrità è il nome del tipo TContext.

Nell'esempio seguente viene registrato un DbContext oggetto e un oggetto associato DbContextHealthCheck:

builder.Services.AddDbContext<SampleDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddHealthChecks()
    .AddDbContextCheck<SampleDbContext>();

Separare i probe di idoneità e di attività

In alcuni scenari di hosting viene usata una coppia di controlli di integrità per distinguere due stati dell'app:

  • Idoneità indica se l'app è in esecuzione normalmente, ma non è pronta per ricevere le richieste.
  • Liveness indica se un'app si è arrestata in modo anomalo e deve essere riavviata.

Si consideri l'esempio seguente: un'app deve scaricare un file di configurazione di grandi dimensioni prima che sia pronto per elaborare le richieste. Non si vuole riavviare l'app se il download iniziale non riesce perché l'app può riprovare a scaricare il file più volte. Viene usato un probe di attività per descrivere la durata del processo, non vengono eseguiti altri controlli. Si vuole anche impedire che le richieste vengano inviate all'app prima che il download del file di configurazione abbia avuto esito positivo. Usiamo un probe di idoneità per indicare uno stato "non pronto" fino a quando il download non riesce e l'app è pronta per ricevere le richieste.

L'attività in background seguente simula un processo di avvio che richiede circa 15 secondi. Al termine, l'attività imposta la StartupHealthCheck.StartupCompleted proprietà su true:

public class StartupBackgroundService : BackgroundService
{
    private readonly StartupHealthCheck _healthCheck;

    public StartupBackgroundService(StartupHealthCheck healthCheck)
        => _healthCheck = healthCheck;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Simulate the effect of a long-running task.
        await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);

        _healthCheck.StartupCompleted = true;
    }
}

Segnala StartupHealthCheck il completamento dell'attività di avvio a esecuzione prolungata ed espone la StartupCompleted proprietà che viene impostata dal servizio in background:

public class StartupHealthCheck : IHealthCheck
{
    private volatile bool _isReady;

    public bool StartupCompleted
    {
        get => _isReady;
        set => _isReady = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        if (StartupCompleted)
        {
            return Task.FromResult(HealthCheckResult.Healthy("The startup task has completed."));
        }

        return Task.FromResult(HealthCheckResult.Unhealthy("That startup task is still running."));
    }
}

Il controllo di integrità viene registrato con AddCheck in Program.cs insieme al servizio ospitato. Poiché il servizio ospitato deve impostare la proprietà nel controllo integrità, il controllo integrità viene registrato anche nel contenitore del servizio come singleton:

builder.Services.AddHostedService<StartupBackgroundService>();
builder.Services.AddSingleton<StartupHealthCheck>();

builder.Services.AddHealthChecks()
    .AddCheck<StartupHealthCheck>(
        "Startup",
        tags: new[] { "ready" });

Per creare due endpoint di controllo integrità diversi, chiamare MapHealthChecks due volte:

app.MapHealthChecks("/healthz/ready", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("ready")
});

app.MapHealthChecks("/healthz/live", new HealthCheckOptions
{
    Predicate = _ => false
});

L'esempio precedente crea gli endpoint di controllo integrità seguenti:

  • /healthz/ready per il controllo di conformità. Il controllo di conformità filtra i controlli di integrità a quelli contrassegnati con ready.
  • /healthz/live per il controllo del liveness. Il controllo attività filtra tutti i controlli di integrità restituendo false nel HealthCheckOptions.Predicate delegato. Per altre informazioni sul filtro dei controlli di integrità, vedere Filtrare i controlli di integrità in questo articolo.

Prima del completamento dell'attività di avvio, l'endpoint /healthz/ready segnala uno Unhealthy stato. Al termine dell'attività di avvio, questo endpoint segnala uno Healthy stato. L'endpoint /healthz/live esclude tutti i controlli e segnala uno Healthy stato per tutte le chiamate.

Esempio di Kubernetes

L'uso di controlli di idoneità e attività separati è utile in un ambiente come Kubernetes. In Kubernetes potrebbe essere necessaria un'app per eseguire operazioni di avvio che richiedono molto tempo prima di accettare richieste, ad esempio un test della disponibilità del database sottostante. L'uso di controlli separati consente all'agente di orchestrazione di distinguere se l'app è funzionante, ma non è ancora pronta o se l'app non è stata avviata. Per altre informazioni sui probe di idoneità e di attività in Kubernetes, vedere Configure Liveness and Readiness Probes (Configurare i probe di attività e di idoneità in Kubernetes) nella documentazione di Kubernetes.

L'esempio seguente illustra la configurazione di un probe di idoneità di Kubernetes:

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /healthz/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

Distribuire una libreria di controllo di integrità

Per distribuire un controllo di integrità come libreria:

  1. Scrivere un controllo di integrità che implementa l'interfaccia IHealthCheck come classe autonoma. La classe può basarsi su inserimento delle dipendenze, attivazione del tipo e opzioni denominate per accedere ai dati di configurazione.

  2. Scrivere un metodo di estensione con i parametri che l'app chiama nel metodo Program.cs. Si consideri il controllo integrità di esempio seguente, che accetta arg1 e arg2 come parametri del costruttore:

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);
    

    La firma precedente indica che il controllo integrità richiede dati personalizzati per elaborare la logica del probe del controllo integrità. I dati vengono forniti al delegato usato per creare l'istanza del controllo di integrità quando il controllo di integrità viene registrato con un metodo di estensione. Nell'esempio seguente il chiamante specifica:

    • arg1: punto dati integer per il controllo integrità.
    • arg2: argomento stringa per il controllo integrità.
    • name: nome facoltativo del controllo integrità. Se null, viene usato un valore predefinito.
    • failureStatus: oggetto facoltativo HealthStatusche viene segnalato per uno stato di errore. Se null, viene usato HealthStatus.Unhealthy.
    • tags: raccolta facoltativa IEnumerable<string> di tag.
    public static class SampleHealthCheckBuilderExtensions
    {
        private const string DefaultName = "Sample";
    
        public static IHealthChecksBuilder AddSampleHealthCheck(
            this IHealthChecksBuilder healthChecksBuilder,
            int arg1,
            string arg2,
            string? name = null,
            HealthStatus? failureStatus = null,
            IEnumerable<string>? tags = default)
        {
            return healthChecksBuilder.Add(
                new HealthCheckRegistration(
                    name ?? DefaultName,
                    _ => new SampleHealthCheckWithArgs(arg1, arg2),
                    failureStatus,
                    tags));
        }
    }
    

Server di pubblicazione dei controlli di integrità

Quando IHealthCheckPublisher viene aggiunto al contenitore del servizio, il sistema di controllo dell'integrità esegue periodicamente i controlli di integrità e chiama PublishAsync con il risultato. Questo processo è utile in uno scenario di sistema di monitoraggio dell'integrità basato su push che prevede che ogni processo chiami periodicamente il sistema di monitoraggio per determinare l'integrità.

HealthCheckPublisherOptions consente di impostare:

  • Delay: ritardo iniziale applicato dopo l'avvio dell'app prima dell'esecuzione delle IHealthCheckPublisher istanze. Il ritardo viene applicato una sola volta all'avvio e non si applica alle iterazioni successive. Il valore predefinito è cinque secondi.
  • Period: periodo di IHealthCheckPublisher esecuzione. Il valore predefinito è 30 secondi.
  • Predicate: se Predicate è null (impostazione predefinita), il servizio di pubblicazione controllo integrità esegue tutti i controlli di integrità registrati. Per eseguire un subset dei controlli di integrità, specificare una funzione che filtra il set di controlli. Il predicato viene valutato per ogni periodo.
  • Timeout: timeout per l'esecuzione dei controlli di integrità per tutte le IHealthCheckPublisher istanze. Usare InfiniteTimeSpan per l'esecuzione senza un timeout. Il valore predefinito è 30 secondi.

Nell'esempio seguente viene illustrato il layout di un editore di integrità:

public class SampleHealthCheckPublisher : IHealthCheckPublisher
{
    public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            // ...
        }
        else
        {
            // ...
        }

        return Task.CompletedTask;
    }
}

La HealthCheckPublisherOptions classe fornisce proprietà per la configurazione del comportamento dell'autore del controllo integrità.

Nell'esempio seguente viene registrato un server di pubblicazione del controllo integrità come singleton e viene configurato HealthCheckPublisherOptions:

builder.Services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = healthCheck => healthCheck.Tags.Contains("sample");
});

builder.Services.AddSingleton<IHealthCheckPublisher, SampleHealthCheckPublisher>();

AspNetCore.Diagnostics.HealthChecks:

  • Include editori per diversi sistemi, tra cui Application Insights.
  • Non è gestito o supportato da Microsoft.

Controlli di integrità individuali

Delay e Period possono essere impostati singolarmente HealthCheckRegistration . Ciò è utile quando si desidera eseguire alcuni controlli di integrità a una velocità diversa rispetto al periodo impostato in HealthCheckPublisherOptions.

Il codice seguente imposta e Delay Period per :SampleHealthCheck1

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks()
   .Add(new HealthCheckRegistration(
       name: "SampleHealthCheck1",
       instance: new SampleHealthCheck(),
       failureStatus: null,
       tags: null,
       timeout: default)
   {
       Delay = TimeSpan.FromSeconds(40),
       Period = TimeSpan.FromSeconds(30)
   });

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Inserimento delle dipendenze e controlli di integrità

È possibile usare l'inserimento delle dipendenze per utilizzare un'istanza di un oggetto specifico Type all'interno di una classe Controllo integrità. L'inserimento delle dipendenze può essere utile per inserire opzioni o una configurazione globale in un controllo integrità. L'uso dell'inserimento delle dipendenze non è uno scenario comune per configurare i controlli di integrità. In genere, ogni controllo integrità è piuttosto specifico del test effettivo ed è configurato usando IHealthChecksBuilder i metodi di estensione.

L'esempio seguente mostra un esempio di controllo integrità che recupera un oggetto di configurazione tramite l'inserimento delle dipendenze:

public class SampleHealthCheckWithDI : IHealthCheck
{
    private readonly SampleHealthCheckWithDiConfig _config;

    public SampleHealthCheckWithDI(SampleHealthCheckWithDiConfig config)
        => _config = config;

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // use _config ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

E SampleHealthCheckWithDiConfig il controllo integrità deve essere aggiunto al contenitore del servizio :

builder.Services.AddSingleton<SampleHealthCheckWithDiConfig>(new SampleHealthCheckWithDiConfig
{
    BaseUriToCheck = new Uri("https://sample.contoso.com/api/")
});
builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheckWithDI>(
        "With Dependency Injection",
        tags: new[] { "inject" });

UseHealthChecks e MapHealthChecks

Esistono due modi per rendere i controlli di integrità accessibili ai chiamanti:

  • UseHealthChecks registra il middleware per la gestione delle richieste di controlli di integrità nella pipeline middleware.
  • MapHealthChecks registra un endpoint dei controlli di integrità. L'endpoint viene confrontato ed eseguito insieme ad altri endpoint nell'app.

Il vantaggio dell'uso MapHealthChecks di oltre UseHealthChecks è la possibilità di usare il middleware con riconoscimento degli endpoint, ad esempio l'autorizzazione, e di avere un maggiore controllo granulare sui criteri di corrispondenza. Il vantaggio principale dell'uso UseHealthChecks di over MapHealthChecks è controllare esattamente dove vengono eseguiti i controlli di integrità nella pipeline middleware.

UseHealthChecks:

  • Termina la pipeline quando una richiesta corrisponde all'endpoint del controllo integrità. Il corto circuito è spesso auspicabile perché evita operazioni non necessarie, ad esempio la registrazione e altri middleware.
  • Viene usato principalmente per configurare il middleware di controllo integrità nella pipeline.
  • Può corrispondere a qualsiasi percorso di una porta con un null oggetto o vuoto PathString. Consente di eseguire un controllo di integrità su qualsiasi richiesta effettuata sulla porta specificata.
  • Codice sorgente

MapHealthChecks Permette:

  • Terminando la pipeline quando una richiesta corrisponde all'endpoint del controllo integrità, chiamando ShortCircuit. Ad esempio: app.MapHealthChecks("/healthz").ShortCircuit();. Per altre informazioni, vedere Middleware a corto circuito dopo il routing.
  • Mapping di route o endpoint specifici per i controlli di integrità.
  • Personalizzazione dell'URL o del percorso in cui l'endpoint del controllo integrità è accessibile.
  • Mapping di più endpoint di controllo integrità con route o configurazioni diverse. Supporto di più endpoint:
    • Abilita endpoint separati per diversi tipi di controlli di integrità o componenti.
    • Viene usato per distinguere i diversi aspetti dell'integrità dell'app o applicare configurazioni specifiche ai subset di controlli di integrità.
  • Codice sorgente

Risorse aggiuntive

Nota

Questo articolo è stato in parte creato con l'aiuto dell'intelligenza artificiale. Prima della pubblicazione, un autore ha rivisto e revisionato il contenuto secondo necessità. Vedere I nostri principi per l'uso di contenuto generato da intelligenza artificiale in Microsoft Learn.

ASP.NET Core offre il middleware e le librerie di controlli di integrità per segnalare l'integrità dei componenti dell'infrastruttura delle app.

I controlli di integrità vengono esposti da un'app come endpoint HTTP. Gli endpoint di controllo integrità possono essere configurati per vari scenari di monitoraggio in tempo reale:

  • I probe di integrità possono essere usati dagli agenti di orchestrazione e dai servizi di bilanciamento del carico per controllare lo stato di un'app. Ad esempio, un agente di orchestrazione potrebbe rispondere a controllo di integrità non superato arrestando una distribuzione in sequenza o riavviando un contenitore. Un servizio di bilanciamento del carico potrebbe reagire a un'app non integra trasferendo il traffico dall'istanza con errori a un'istanza integra.
  • È possibile monitorare lo stato di integrità di memoria, disco e altre risorse fisiche del server.
  • I controlli di integrità possono testare le dipendenze di un'app, ad esempio i database e gli endpoint di servizio esterni, per verificare la disponibilità e il normale funzionamento.

Visualizzare o scaricare il codice di esempio (procedura per il download)

L'app di esempio include esempi degli scenari descritti in questo articolo. Per eseguire l'app di esempio per un determinato scenario, usare il comando dotnet run dalla cartella del progetto in una shell dei comandi. Per informazioni dettagliate su come usare l'app di esempio, vedere il file dell'app di README.md esempio e le descrizioni dello scenario in questo articolo.

Prerequisiti

I controlli di integrità vengono in genere usati con un servizio di monitoraggio esterno o un agente di orchestrazione del contenitore per controllare lo stato di un'app. Prima di aggiungere i controlli di integrità a un'app, decidere quale sistema di monitoraggio usare. Il sistema di monitoraggio determina quali tipi di controlli di integrità creare e come configurare i relativi endpoint.

Il Microsoft.AspNetCore.Diagnostics.HealthChecks pacchetto viene fatto riferimento in modo implicito per ASP.NET app Core. Per eseguire controlli di integrità usando Entity Framework Core, aggiungere un riferimento al Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore pacchetto.

L'app di esempio include il codice di avvio per illustrare i controlli di integrità per diversi scenari. Lo scenario del probe del database controlla l'integrità di una connessione di database tramite AspNetCore.Diagnostics.HealthChecks. Lo scenario probe DbContext controlla un database usando un oggetto EF CoreDbContext. Per esplorare gli scenari relativi ai database, l'app di esempio:

Nota

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Un altro scenario relativo ai controlli di integrità illustra come filtrare i controlli di integrità per una porta di gestione. L'app di esempio richiede di creare un Properties/launchSettings.json file che includa l'URL di gestione e la porta di gestione. Per altre informazioni, vedere la sezione Filtrare in base alla porta.

Probe di integrità di base

Per molte app, una configurazione del probe di integrità di base, che segnala la disponibilità dell'app per elaborare le richieste (attività), è sufficiente per individuare lo stato dell'app.

La configurazione di base registra i servizi di controllo integrità e chiama il middleware controlli di integrità per rispondere a un endpoint URL con una risposta di integrità. Per impostazione predefinita, non vengono registrati controlli di integrità specifici per testare particolari dipendenze o sottosistemi. L'app viene considerata integra se può rispondere all'URL dell'endpoint di integrità. Il writer di risposta predefinito scrive lo stato (HealthStatus) come risposta in testo non crittografato al client, che indica uno HealthStatus.Healthystato , HealthStatus.Degradedo HealthStatus.Unhealthy .

Registrare i servizi dei controlli di integrità con AddHealthChecks in Startup.ConfigureServices. Creare un endpoint di controllo dell'integrità chiamando MapHealthChecks in Startup.Configure.

Nell'app di esempio viene creato l'endpoint di controllo integrità in /health (BasicStartup.cs):

public class BasicStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHealthChecks();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHealthChecks("/health");
        });
    }
}

Per eseguire lo scenario di configurazione di base usando l'app di esempio, eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario basic

Esempio Docker

Docker offre una direttiva HEALTHCHECK predefinita che può essere usata per controllare lo stato di un'app che usa la configurazione dei controlli di integrità di base:

HEALTHCHECK CMD curl --fail http://localhost:5000/health || exit

Creare controlli di integrità

I controlli di integrità vengono creati implementando l'interfaccia IHealthCheck. Il metodo CheckHealthAsync restituisce HealthCheckResult che indica l'integrità come Healthy, Degraded o Unhealthy. Il risultato viene scritto come risposta di testo non crittografato con un codice di stato configurabile. La configurazione viene descritta nella sezione Opzioni dei controlli di integrità. HealthCheckResult può anche restituire coppie chiave-valore facoltative.

La classe seguente ExampleHealthCheck illustra il layout di un controllo integrità. La logica dei controlli di integrità viene inserita nel CheckHealthAsync metodo . Nell'esempio seguente viene impostata una variabile fittizia, , healthCheckResultHealthysu true. Se il valore di healthCheckResultHealthy è impostato su false, viene restituito lo HealthCheckRegistration.FailureStatus stato .

public class ExampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var healthCheckResultHealthy = true;

        if (healthCheckResultHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(context.Registration.FailureStatus, 
            "An unhealthy result."));
    }
}

Se CheckHealthAsync genera un'eccezione durante il controllo, viene restituito un nuovo HealthReportEntry oggetto con il relativo HealthReportEntry.Status set su FailureStatus, definito da AddCheck (vedere la sezione Registrare i servizi di controllo integrità) e include l'eccezione interna che ha inizialmente causato l'errore di controllo. l'oggetto Description è impostato sul messaggio dell'eccezione.

Registrare i servizi di controllo dell'integrità

Il ExampleHealthCheck tipo viene aggiunto ai servizi di controllo integrità con AddCheck in Startup.ConfigureServices:

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>("example_health_check");

L'overload AddCheck illustrato nell'esempio seguente imposta lo stato di errore (HealthStatus) per segnalare quando il controllo di integrità indica un errore. Se lo stato di errore è impostato su null (impostazione predefinita), viene segnalato HealthStatus.Unhealthy. Questo overload è uno scenario utile per gli autori di librerie, in cui lo stato di errore indicato dalla libreria viene applicato dall'app quando si verifica un errore di controllo dell'integrità se l'implementazione del controllo dell'integrità rispetta l'impostazione.

Si possono usare tag per filtrare i controlli di integrità, come illustrato più avanti nella sezione Filtrare i controlli di integrità.

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>(
        "example_health_check",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "example" });

AddCheck può anche eseguire una funzione lambda. Nell'esempio seguente il nome del controllo di integrità viene specificato come Example e il controllo restituisce sempre uno stato integro:

services.AddHealthChecks()
    .AddCheck("Example", () =>
        HealthCheckResult.Healthy("Example is OK!"), tags: new[] { "example" });

Chiamare AddTypeActivatedCheck per passare argomenti a un'implementazione del controllo integrità. Nell'esempio seguente accetta TestHealthCheckWithArgs un numero intero e una stringa da usare quando CheckHealthAsync viene chiamato:

private class TestHealthCheckWithArgs : IHealthCheck
{
    public TestHealthCheckWithArgs(int i, string s)
    {
        I = i;
        S = s;
    }

    public int I { get; set; }

    public string S { get; set; }

    public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, 
        CancellationToken cancellationToken = default)
    {
        ...
    }
}

TestHealthCheckWithArgs viene registrato chiamando AddTypeActivatedCheck con l'intero e la stringa passata all'implementazione:

services.AddHealthChecks()
    .AddTypeActivatedCheck<TestHealthCheckWithArgs>(
        "test", 
        failureStatus: HealthStatus.Degraded, 
        tags: new[] { "example" }, 
        args: new object[] { 5, "string" });

Usare il routing dei controlli di integrità

In Startup.Configurechiamare MapHealthChecks sul generatore di endpoint con l'URL dell'endpoint o il percorso relativo:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
});

Richiedi host

Chiamare RequireHost per specificare uno o più host consentiti per l'endpoint di controllo integrità. Gli host devono essere Unicode anziché punycode e possono includere una porta. Se non viene fornita una raccolta, viene accettato qualsiasi host.

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("www.contoso.com:5001");
});

Per altre informazioni, vedere la sezione Filtrare in base alla porta.

Richiedi autorizzazione

Chiamare RequireAuthorization per eseguire il middleware di autorizzazione nell'endpoint della richiesta di controllo integrità. Un RequireAuthorization overload accetta uno o più criteri di autorizzazione. Se non viene specificato un criterio, vengono usati i criteri di autorizzazione predefiniti.

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireAuthorization();
});

Abilitare richieste tra le origini (CORS)

Anche se l'esecuzione manuale dei controlli di integrità da un browser non è uno scenario d'uso comune, il middleware CORS può essere abilitato chiamando RequireCors sugli endpoint dei controlli di integrità. Un RequireCors overload accetta un delegato del generatore di criteri CORS (CorsPolicyBuilder) o un nome di criteri. Se non viene specificato un criterio, viene usato il criterio CORS predefinito. Per altre informazioni, vedere Abilitare le richieste tra le origini (CORS) in ASP.NET Core.

Opzioni dei controlli di integrità

HealthCheckOptions consente di personalizzare il comportamento dei controlli di integrità:

Filtrare i controlli di integrità

Per impostazione predefinita, il middleware dei controlli di integrità esegue tutti i controlli di integrità registrati. Per eseguire un subset dei controlli di integrità, specificare una funzione che restituisce un valore booleano all'opzione Predicate. Nell'esempio seguente il controllo di integrità Bar viene filtrato in base al tag (bar_tag) nell'istruzione condizionale della funzione, dove true viene restituito solo se la proprietà Tags del controllo di integrità corrisponde a foo_tag o a baz_tag:

In Startup.ConfigureServices:

services.AddHealthChecks()
    .AddCheck("Foo", () =>
        HealthCheckResult.Healthy("Foo is OK!"), tags: new[] { "foo_tag" })
    .AddCheck("Bar", () =>
        HealthCheckResult.Unhealthy("Bar is unhealthy!"), tags: new[] { "bar_tag" })
    .AddCheck("Baz", () =>
        HealthCheckResult.Healthy("Baz is OK!"), tags: new[] { "baz_tag" });

In Startup.Configurefiltra Predicate il controllo di integrità "Barra". Solo Foo e Baz execute:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("foo_tag") ||
            check.Tags.Contains("baz_tag")
    });
});

Personalizzare il codice di stato HTTP

Usare ResultStatusCodes per personalizzare il mapping dello stato di integrità dei codici di stato HTTP. Le assegnazioni StatusCodes seguenti sono i valori predefiniti usati dal middleware. Modificare i valori dei codici di stato in base ai requisiti.

In Startup.Configure:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResultStatusCodes =
        {
            [HealthStatus.Healthy] = StatusCodes.Status200OK,
            [HealthStatus.Degraded] = StatusCodes.Status200OK,
            [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
        }
    });
});

Eliminare le intestazioni della cache

AllowCachingResponses controlla se il middleware controlli di integrità aggiunge intestazioni HTTP a una risposta probe per impedire la memorizzazione nella cache delle risposte. Se il valore è false (impostazione predefinita), il middleware imposta le intestazioni Cache-Control, Expires e Pragma o ne esegue l'override per impedire la memorizzazione della risposta nella cache. Se il valore è true, il middleware non modifica le intestazioni della risposta nella cache.

In Startup.Configure:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        AllowCachingResponses = true
    });
});

Personalizzare l'output

In Startup.Configureimpostare l'opzione HealthCheckOptions.ResponseWriter su un delegato per la scrittura della risposta:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
});

Il delegato predefinito scrive una risposta in testo non crittografato minima con il valore di stringa HealthReport.Status. I delegati personalizzati seguenti generano una risposta JSON personalizzata.

Il primo esempio dell'app di esempio illustra come usare System.Text.Json:

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions
    {
        Indented = true
    };

    using (var stream = new MemoryStream())
    {
        using (var writer = new Utf8JsonWriter(stream, options))
        {
            writer.WriteStartObject();
            writer.WriteString("status", result.Status.ToString());
            writer.WriteStartObject("results");
            foreach (var entry in result.Entries)
            {
                writer.WriteStartObject(entry.Key);
                writer.WriteString("status", entry.Value.Status.ToString());
                writer.WriteString("description", entry.Value.Description);
                writer.WriteStartObject("data");
                foreach (var item in entry.Value.Data)
                {
                    writer.WritePropertyName(item.Key);
                    JsonSerializer.Serialize(
                        writer, item.Value, item.Value?.GetType() ??
                        typeof(object));
                }
                writer.WriteEndObject();
                writer.WriteEndObject();
            }
            writer.WriteEndObject();
            writer.WriteEndObject();
        }

        var json = Encoding.UTF8.GetString(stream.ToArray());

        return context.Response.WriteAsync(json);
    }
}

Il secondo esempio illustra come usare Newtonsoft.Json:

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json";

    var json = new JObject(
        new JProperty("status", result.Status.ToString()),
        new JProperty("results", new JObject(result.Entries.Select(pair =>
            new JProperty(pair.Key, new JObject(
                new JProperty("status", pair.Value.Status.ToString()),
                new JProperty("description", pair.Value.Description),
                new JProperty("data", new JObject(pair.Value.Data.Select(
                    p => new JProperty(p.Key, p.Value))))))))));

    return context.Response.WriteAsync(
        json.ToString(Formatting.Indented));
}

Nell'app di esempio impostare come commento la direttiva del SYSTEM_TEXT_JSON preprocessore in CustomWriterStartup.cs per abilitare la Newtonsoft.Json versione di WriteResponse.

L'API dei controlli di integrità non fornisce il supporto predefinito per i formati restituiti JSON complessi perché il formato è specifico della scelta del sistema di monitoraggio. Personalizzare la risposta negli esempi precedenti in base alle esigenze. Per altre informazioni sulla serializzazione JSON con System.Text.Json, vedere Come serializzare e deserializzare JSON in .NET.

Probe del database

Un controllo di integrità può specificare una query di database da eseguire come test booleano per indicare se il database sta rispondendo normalmente.

L'app di esempio usa AspNetCore.Diagnostics.HealthChecks, una libreria di controllo integrità per le app core ASP.NET, per eseguire un controllo integrità in un database di SQL Server. AspNetCore.Diagnostics.HealthChecks esegue una query SELECT 1 sul database per confermare che la connessione al database sia integra.

Avviso

Quando si controlla una connessione di database con una query, scegliere una query che viene restituita rapidamente. Dall'approccio alla query possono derivare il sovraccarico del database e il degrado delle prestazioni. Nella maggior parte dei casi, l'esecuzione di una query di test non è necessaria. È sufficiente stabilire una connessione al database. Se invece è necessario eseguire una query, scegliere una semplice query SELECT, ad esempio SELECT 1.

Includere un riferimento al pacchetto a AspNetCore.HealthChecks.SqlServer.

Specificare un stringa di connessione di database valido nel appsettings.json file dell'app di esempio. L'app usa una database di SQL Server denominato HealthCheckSample:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=HealthCheckSample;Trusted_Connection=True;MultipleActiveResultSets=true;ConnectRetryCount=0"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "Console": {
      "IncludeScopes": "true"
    }
  },
  "AllowedHosts": "*"
}

Registrare i servizi dei controlli di integrità con AddHealthChecks in Startup.ConfigureServices. L'app di esempio chiama il AddSqlServer metodo con il stringa di connessione del database (DbHealthStartup.cs):

services.AddHealthChecks()
    .AddSqlServer(Configuration["ConnectionStrings:DefaultConnection"]);

Un endpoint di controllo dell'integrità viene creato chiamando MapHealthChecks in Startup.Configure:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

Per eseguire lo scenario di probe del database di base usando l'app di esempio, eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario db

Nota

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Probe DbContext di Entity Framework Core

Il DbContext controllo conferma che l'app può comunicare con il database configurato per un oggetto EF CoreDbContext. Il controllo DbContext è supportato nelle app che:

AddDbContextCheck<TContext> registra un controllo di integrità per un DbContext. DbContext viene reso disponibile come TContext al metodo. È disponibile un overload per configurare lo stato di errore, i tag e una query di test personalizzata.

Per impostazione predefinita:

  • Il DbContextHealthCheck metodo chiama EF Coreil metodo .CanConnectAsync È possibile determinare l'operazione da eseguire quando si controlla l'integrità usando gli overload del metodo AddDbContextCheck.
  • Il nome del controllo di integrità è il nome del tipo TContext.

Nell'app di esempio viene AppDbContext fornito AddDbContextCheck e registrato come servizio in Startup.ConfigureServices (DbContextHealthStartup.cs):

services.AddHealthChecks()
    .AddDbContextCheck<AppDbContext>();

services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(
        Configuration["ConnectionStrings:DefaultConnection"]);
});

Un endpoint di controllo dell'integrità viene creato chiamando MapHealthChecks in Startup.Configure:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

Per eseguire lo scenario di probe DbContext usando l'app di esempio, verificare che il database specificato dalla stringa di connessione non esista nell'istanza di SQL Server. Se il database esiste, eliminarlo.

Eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario dbcontext

Dopo che l'app è in esecuzione, controllare lo stato di integrità effettuando una richiesta all'endpoint /health in un browser. Il database e AppDbContext non esistono, quindi l'app fornisce la risposta seguente:

Unhealthy

Attivare l'app di esempio per creare il database. Effettuare una richiesta a /createdatabase. L'app risponde:

Creating the database...
Done!
Navigate to /health to see the health status.

Effettuare una richiesta all'endpoint /health. Il database e il contesto esistono, quindi l'app risponde:

Healthy

Attivare l'app di esempio per eliminare il database. Effettuare una richiesta a /deletedatabase. L'app risponde:

Deleting the database...
Done!
Navigate to /health to see the health status.

Effettuare una richiesta all'endpoint /health. L'app fornisce una risposta non integra:

Unhealthy

Separare i probe di idoneità e di attività

In alcuni scenari di hosting viene usata una coppia di controlli di integrità per distinguere due stati dell'app:

  • Idoneità indica se l'app è in esecuzione normalmente, ma non è pronta per ricevere le richieste.
  • Liveness indica se un'app si è arrestata in modo anomalo e deve essere riavviata.

Si consideri l'esempio seguente: un'app deve scaricare un file di configurazione di grandi dimensioni prima che sia pronto per elaborare le richieste. Non si vuole riavviare l'app se il download iniziale non riesce perché l'app può riprovare a scaricare il file più volte. Viene usato un probe di attività per descrivere la durata del processo, non vengono eseguiti altri controlli. Si vuole anche impedire che le richieste vengano inviate all'app prima che il download del file di configurazione abbia avuto esito positivo. Usiamo un probe di idoneità per indicare uno stato "non pronto" fino a quando il download non riesce e l'app è pronta per ricevere le richieste.

L'app di esempio contiene un controllo di integrità per segnalare il completamento dell'attività di avvio con esecuzione prolungata in un servizio ospitato. StartupHostedServiceHealthCheck espone una proprietà , StartupTaskCompleted, su cui il servizio ospitato può essere impostato true al termine dell'attività a esecuzione prolungata (StartupHostedServiceHealthCheck.cs):

public class StartupHostedServiceHealthCheck : IHealthCheck
{
    private volatile bool _startupTaskCompleted = false;

    public string Name => "slow_dependency_check";

    public bool StartupTaskCompleted
    {
        get => _startupTaskCompleted;
        set => _startupTaskCompleted = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        if (StartupTaskCompleted)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("The startup task is finished."));
        }

        return Task.FromResult(
            HealthCheckResult.Unhealthy("The startup task is still running."));
    }
}

L'attività in background a esecuzione prolungata viene avviata da un servizio ospitato (Services/StartupHostedService). Al termine dell'attività, StartupHostedServiceHealthCheck.StartupTaskCompleted viene impostata su true:

public class StartupHostedService : IHostedService, IDisposable
{
    private readonly int _delaySeconds = 15;
    private readonly ILogger _logger;
    private readonly StartupHostedServiceHealthCheck _startupHostedServiceHealthCheck;

    public StartupHostedService(ILogger<StartupHostedService> logger,
        StartupHostedServiceHealthCheck startupHostedServiceHealthCheck)
    {
        _logger = logger;
        _startupHostedServiceHealthCheck = startupHostedServiceHealthCheck;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is starting.");

        // Simulate the effect of a long-running startup task.
        Task.Run(async () =>
        {
            await Task.Delay(_delaySeconds * 1000);

            _startupHostedServiceHealthCheck.StartupTaskCompleted = true;

            _logger.LogInformation("Startup Background Service has started.");
        });

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is stopping.");

        return Task.CompletedTask;
    }

    public void Dispose()
    {
    }
}

Il controllo di integrità viene registrato con AddCheck in Startup.ConfigureServices insieme al servizio ospitato. Poiché il servizio ospitato deve impostare la proprietà nel controllo integrità, il controllo integrità viene registrato anche nel contenitore del servizio (LivenessProbeStartup.cs):

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

Un endpoint di controllo dell'integrità viene creato chiamando MapHealthChecks in Startup.Configure. Nell'app di esempio gli endpoint di controllo integrità vengono creati in:

  • /health/ready per il controllo di conformità. Il controllo di idoneità filtra i controlli di integrità per il controllo di integrità con il tag ready.
  • /health/live per il controllo del liveness. Il controllo attività filtra l'oggetto StartupHostedServiceHealthCheck restituendo false in HealthCheckOptions.Predicate (per altre informazioni, vedere Filtrare i controlli di integrità)

Nel codice di esempio seguente:

  • Il controllo di conformità usa tutti i controlli registrati con il tag 'ready'.
  • Predicate Esclude tutti i controlli e restituisce un valore 200-Ok.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

Per eseguire lo scenario di configurazione di idoneità/attività usando l'app di esempio, eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario liveness

In a browser visitare più volte /health/ready per 15 secondi. Il controllo di integrità segnala Unhealthy per i primi 15 secondi. Dopo 15 secondi, l'endpoint segnala Healthy, che indica il completamento dell'attività con esecuzione prolungata da parte del servizio ospitato.

Questo esempio crea anche un server di pubblicazione controllo integrità (IHealthCheckPublisher implementazione) che esegue il primo controllo di idoneità con un ritardo di due secondi. Per altre informazioni, vedere la sezione Server di pubblicazione dei controlli di integrità.

Esempio di Kubernetes

L'uso di controlli di idoneità e attività separati è utile in un ambiente come Kubernetes. In Kubernetes potrebbe essere necessaria un'app per eseguire operazioni di avvio che richiedono molto tempo prima di accettare richieste, ad esempio un test della disponibilità del database sottostante. L'uso di controlli separati consente all'agente di orchestrazione di distinguere se l'app è funzionante, ma non è ancora pronta o se l'app non è stata avviata. Per altre informazioni sui probe di idoneità e di attività in Kubernetes, vedere Configure Liveness and Readiness Probes (Configurare i probe di attività e di idoneità in Kubernetes) nella documentazione di Kubernetes.

L'esempio seguente illustra la configurazione di un probe di idoneità di Kubernetes:

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /health/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

Probe basato sulle metriche con un writer di risposta personalizzata

L'app di esempio illustra un controllo di integrità della memoria con un writer di risposta personalizzata.

MemoryHealthCheck segnala uno stato danneggiato se l'app usa più di una determinata soglia di memoria (1 GB nell'app di esempio). HealthCheckResult Include le informazioni di Garbage Collector (GC) per l'app (MemoryHealthCheck.cs):

public class MemoryHealthCheck : IHealthCheck
{
    private readonly IOptionsMonitor<MemoryCheckOptions> _options;

    public MemoryHealthCheck(IOptionsMonitor<MemoryCheckOptions> options)
    {
        _options = options;
    }

    public string Name => "memory_check";

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var options = _options.Get(context.Registration.Name);

        // Include GC information in the reported diagnostics.
        var allocated = GC.GetTotalMemory(forceFullCollection: false);
        var data = new Dictionary<string, object>()
        {
            { "AllocatedBytes", allocated },
            { "Gen0Collections", GC.CollectionCount(0) },
            { "Gen1Collections", GC.CollectionCount(1) },
            { "Gen2Collections", GC.CollectionCount(2) },
        };
        var status = (allocated < options.Threshold) ?
            HealthStatus.Healthy : context.Registration.FailureStatus;

        return Task.FromResult(new HealthCheckResult(
            status,
            description: "Reports degraded status if allocated bytes " +
                $">= {options.Threshold} bytes.",
            exception: null,
            data: data));
    }
}

Registrare i servizi dei controlli di integrità con AddHealthChecks in Startup.ConfigureServices. Invece di abilitare il controllo di integrità passandolo ad AddCheck, MemoryHealthCheck viene registrato come servizio. Tutti i servizi registrati da IHealthCheck sono disponibili per il middleware e i servizi di controllo dell'integrità. È consigliabile registrare i servizi di controllo dell'integrità come servizi Singleton.

Nell'app CustomWriterStartup.cs di esempio:

services.AddHealthChecks()
    .AddMemoryHealthCheck("memory");

Un endpoint di controllo dell'integrità viene creato chiamando MapHealthChecks in Startup.Configure. Viene fornito un delegato WriteResponse alla proprietà ResponseWriter per visualizzare una risposta JSON personalizzata quando il controllo di integrità viene eseguito:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
}

Il WriteResponse delegato formatta l'oggetto CompositeHealthCheckResult in un oggetto JSON e restituisce l'output JSON per la risposta al controllo integrità. Per altre informazioni, vedere la sezione Personalizzare l'output.

Per eseguire lo scenario di probe basato sulle metriche con il writer di risposta personalizzata usando l'app di esempio, eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario writer

Nota

AspNetCore.Diagnostics.HealthChecks include scenari di controllo dell'integrità basato su metriche, tra cui l'archiviazione su disco e i controlli di livezza dei valori massimi.

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Filtrare in base alla porta

MapHealthChecks Chiamare RequireHost con un modello di URL che specifica una porta per limitare le richieste di controllo integrità alla porta specificata. Questo approccio viene in genere usato in un ambiente contenitore per esporre una porta per i servizi di monitoraggio.

L'app di esempio configura la porta usando il provider di configurazione della variabile di ambiente. La porta viene impostata nel launchSettings.json file e passata al provider di configurazione tramite una variabile di ambiente. È anche necessario configurare il server per l'ascolto di richieste sulla porta di gestione.

Per usare l'app di esempio per illustrare la configurazione delle porte di gestione, creare il launchSettings.json file in una Properties cartella.

Il file seguente Properties/launchSettings.json nell'app di esempio non è incluso nei file di progetto dell'app di esempio e deve essere creato manualmente:

{
  "profiles": {
    "SampleApp": {
      "commandName": "Project",
      "commandLineArgs": "",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_URLS": "http://localhost:5000/;http://localhost:5001/",
        "ASPNETCORE_MANAGEMENTPORT": "5001"
      },
      "applicationUrl": "http://localhost:5000/"
    }
  }
}

Registrare i servizi dei controlli di integrità con AddHealthChecks in Startup.ConfigureServices. Creare un endpoint di controllo dell'integrità chiamando MapHealthChecks in Startup.Configure.

Nell'app di esempio, una chiamata a RequireHost sull'endpoint in Startup.Configure specifica la porta di gestione dalla configurazione:

endpoints.MapHealthChecks("/health")
    .RequireHost($"*:{Configuration["ManagementPort"]}");

Gli endpoint vengono creati nell'app di esempio in Startup.Configure. Nel codice di esempio seguente:

  • Il controllo di conformità usa tutti i controlli registrati con il tag 'ready'.
  • Predicate Esclude tutti i controlli e restituisce un valore 200-Ok.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

Nota

È possibile evitare di creare il launchSettings.json file nell'app di esempio impostando la porta di gestione in modo esplicito nel codice. In Program.cs cui viene creato , HostBuilder aggiungere una chiamata a ListenAnyIP e fornire l'endpoint della porta di gestione dell'app. In Configure specificare la porta di ManagementPortStartup.csgestione con RequireHost:

Program.cs:

return new HostBuilder()
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseKestrel()
            .ConfigureKestrel(serverOptions =>
            {
                serverOptions.ListenAnyIP(5001);
            })
            .UseStartup(startupType);
    })
    .Build();

ManagementPortStartup.cs:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("*:5001");
});

Per eseguire lo scenario di configurazione della porta di gestione usando l'app di esempio, eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario port

Distribuire una libreria di controllo di integrità

Per distribuire un controllo di integrità come libreria:

  1. Scrivere un controllo di integrità che implementa l'interfaccia IHealthCheck come classe autonoma. La classe può basarsi su inserimento delle dipendenze, attivazione del tipo e opzioni denominate per accedere ai dati di configurazione.

    Nella logica dei controlli di integrità di CheckHealthAsync:

    • data1 e data2 vengono usati nel metodo per eseguire la logica del controllo di integrità del probe.
    • AccessViolationException viene gestito.

    Quando si verifica un oggetto AccessViolationException , viene FailureStatus restituito con per HealthCheckResult consentire agli utenti di configurare lo stato di errore dei controlli di integrità.

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    namespace SampleApp
    {
        public class ExampleHealthCheck : IHealthCheck
        {
            private readonly string _data1;
            private readonly int? _data2;
    
            public ExampleHealthCheck(string data1, int? data2)
            {
                _data1 = data1 ?? throw new ArgumentNullException(nameof(data1));
                _data2 = data2 ?? throw new ArgumentNullException(nameof(data2));
            }
    
            public async Task<HealthCheckResult> CheckHealthAsync(
                HealthCheckContext context, CancellationToken cancellationToken)
            {
                try
                {
                    return HealthCheckResult.Healthy();
                }
                catch (AccessViolationException ex)
                {
                    return new HealthCheckResult(
                        context.Registration.FailureStatus,
                        description: "An access violation occurred during the check.",
                        exception: ex,
                        data: null);
                }
            }
        }
    }
    
  2. Scrivere un metodo di estensione con i parametri che l'app chiama nel metodo Startup.Configure. Nell'esempio seguente si presuma la firma del metodo di controllo dell'integrità seguente:

    ExampleHealthCheck(string, string, int )
    

    La firma precedente indica che ExampleHealthCheck richiede dati aggiuntivi per elaborare la logica del probe di controllo dell'integrità. I dati vengono forniti al delegato usato per creare l'istanza del controllo di integrità quando il controllo di integrità viene registrato con un metodo di estensione. Nell'esempio seguente il chiamante specifica facoltativamente:

    • nome del controllo integrità (name). Se null, viene usato example_health_check.
    • punto dati stringa per il controllo di integrità (data1).
    • punto dati Integer per il controllo di integrità (data2). Se null, viene usato 1.
    • stato dell'errore (HealthStatus). Il valore predefinito è null. Se null, viene segnalato HealthStatus.Unhealthy come stato di errore.
    • tag (IEnumerable<string>).
    using System.Collections.Generic;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    public static class ExampleHealthCheckBuilderExtensions
    {
        const string DefaultName = "example_health_check";
    
        public static IHealthChecksBuilder AddExampleHealthCheck(
            this IHealthChecksBuilder builder,
            string name = default,
            string data1,
            int data2 = 1,
            HealthStatus? failureStatus = default,
            IEnumerable<string> tags = default)
        {
            return builder.Add(new HealthCheckRegistration(
                name ?? DefaultName,
                sp => new ExampleHealthCheck(data1, data2),
                failureStatus,
                tags));
        }
    }
    

Server di pubblicazione dei controlli di integrità

Quando IHealthCheckPublisher viene aggiunto al contenitore del servizio, il sistema di controllo dell'integrità esegue periodicamente i controlli di integrità e chiama PublishAsync con il risultato. Ciò è utile in uno scenario relativo a un sistema di monitoraggio dell'integrità basato su push, che prevede che ogni processo chiami periodicamente il sistema di monitoraggio per determinare l'integrità.

L'interfaccia IHealthCheckPublisher ha un solo metodo:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions consente di impostare:

  • Delay: ritardo iniziale applicato dopo l'avvio dell'app prima dell'esecuzione delle IHealthCheckPublisher istanze. Il ritardo viene applicato una sola volta all'avvio e non si applica alle iterazioni successive. Il valore predefinito è cinque secondi.
  • Period: periodo di IHealthCheckPublisher esecuzione. Il valore predefinito è 30 secondi.
  • Predicate: se Predicate è null (impostazione predefinita), il servizio di pubblicazione controllo integrità esegue tutti i controlli di integrità registrati. Per eseguire un subset dei controlli di integrità, specificare una funzione che filtra il set di controlli. Il predicato viene valutato per ogni periodo.
  • Timeout: timeout per l'esecuzione dei controlli di integrità per tutte le IHealthCheckPublisher istanze. Usare InfiniteTimeSpan per l'esecuzione senza un timeout. Il valore predefinito è 30 secondi.

Nell'app di esempio, ReadinessPublisher è un'implementazione di IHealthCheckPublisher. Lo stato del controllo integrità viene registrato per ogni controllo a livello di log di:

public class ReadinessPublisher : IHealthCheckPublisher
{
    private readonly ILogger _logger;

    public ReadinessPublisher(ILogger<ReadinessPublisher> logger)
    {
        _logger = logger;
    }

    // The following example is for demonstration purposes only. Health Checks
    // Middleware already logs health checks results. A real-world readiness
    // check in a production app might perform a set of more expensive or
    // time-consuming checks to determine if other resources are responding
    // properly.
    public Task PublishAsync(HealthReport report,
        CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            _logger.LogInformation("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }
        else
        {
            _logger.LogError("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }

        cancellationToken.ThrowIfCancellationRequested();

        return Task.CompletedTask;
    }
}

Nell'esempio di LivenessProbeStartup dell'app di esempio, il controllo di conformità StartupHostedService ha un ritardo di avvio di due secondi e il controllo viene eseguito ogni 30 secondi. Per attivare l'implementazione IHealthCheckPublisher, l'esempio registra ReadinessPublisher come servizio singleton nel contenitore di inserimento delle dipendenze:

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

Nota

AspNetCore.Diagnostics.HealthChecks include editori per diversi sistemi, tra cui Application Insights.

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Limitare i controlli integrità con MapWhen

Usare MapWhen per creare un ramo condizionale della pipeline delle richieste per gli endpoint di controllo integrità.

Nell'esempio seguente la MapWhen pipeline di richiesta viene inramata per attivare il middleware di controlli di integrità se viene ricevuta una richiesta GET per l'endpoint api/HealthCheck :

app.MapWhen(
    context => context.Request.Method == HttpMethod.Get.Method && 
        context.Request.Path.StartsWith("/api/HealthCheck"),
    builder => builder.UseHealthChecks());

app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
});

Per altre informazioni, vedere Middleware ASP.NET Core.

ASP.NET Core offre il middleware e le librerie di controlli di integrità per segnalare l'integrità dei componenti dell'infrastruttura delle app.

I controlli di integrità vengono esposti da un'app come endpoint HTTP. Gli endpoint di controllo integrità possono essere configurati per vari scenari di monitoraggio in tempo reale:

  • I probe di integrità possono essere usati dagli agenti di orchestrazione e dai servizi di bilanciamento del carico per controllare lo stato di un'app. Ad esempio, un agente di orchestrazione potrebbe rispondere a controllo di integrità non superato arrestando una distribuzione in sequenza o riavviando un contenitore. Un servizio di bilanciamento del carico potrebbe reagire a un'app non integra trasferendo il traffico dall'istanza con errori a un'istanza integra.
  • È possibile monitorare lo stato di integrità di memoria, disco e altre risorse fisiche del server.
  • I controlli di integrità possono testare le dipendenze di un'app, ad esempio i database e gli endpoint di servizio esterni, per verificare la disponibilità e il normale funzionamento.

Visualizzare o scaricare il codice di esempio (procedura per il download)

L'app di esempio include esempi degli scenari descritti in questo articolo. Per eseguire l'app di esempio per un determinato scenario, usare il comando dotnet run dalla cartella del progetto in una shell dei comandi. Per informazioni dettagliate su come usare l'app di esempio, vedere il file dell'app di README.md esempio e le descrizioni dello scenario in questo articolo.

Prerequisiti

I controlli di integrità vengono in genere usati con un servizio di monitoraggio esterno o un agente di orchestrazione del contenitore per controllare lo stato di un'app. Prima di aggiungere i controlli di integrità a un'app, decidere quale sistema di monitoraggio usare. Il sistema di monitoraggio determina quali tipi di controlli di integrità creare e come configurare i relativi endpoint.

Il Microsoft.AspNetCore.Diagnostics.HealthChecks pacchetto viene fatto riferimento in modo implicito per ASP.NET app Core. Per eseguire controlli di integrità usando Entity Framework Core, aggiungere un riferimento al Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore pacchetto.

L'app di esempio include il codice di avvio per illustrare i controlli di integrità per diversi scenari. Lo scenario del probe del database controlla l'integrità di una connessione di database tramite AspNetCore.Diagnostics.HealthChecks. Lo scenario probe DbContext controlla un database usando un oggetto EF CoreDbContext. Per esplorare gli scenari relativi ai database, l'app di esempio:

Nota

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Un altro scenario relativo ai controlli di integrità illustra come filtrare i controlli di integrità per una porta di gestione. L'app di esempio richiede di creare un Properties/launchSettings.json file che includa l'URL di gestione e la porta di gestione. Per altre informazioni, vedere la sezione Filtrare in base alla porta.

Probe di integrità di base

Per molte app, una configurazione del probe di integrità di base, che segnala la disponibilità dell'app per elaborare le richieste (attività), è sufficiente per individuare lo stato dell'app.

La configurazione di base registra i servizi di controllo integrità e chiama il middleware controlli di integrità per rispondere a un endpoint URL con una risposta di integrità. Per impostazione predefinita, non vengono registrati controlli di integrità specifici per testare particolari dipendenze o sottosistemi. L'app viene considerata integra se può rispondere all'URL dell'endpoint di integrità. Il writer di risposta predefinito scrive lo stato (HealthStatus) come risposta in testo non crittografato al client, che indica uno HealthStatus.Healthystato , HealthStatus.Degradedo HealthStatus.Unhealthy .

Registrare i servizi dei controlli di integrità con AddHealthChecks in Startup.ConfigureServices. Creare un endpoint di controllo dell'integrità chiamando MapHealthChecks in Startup.Configure.

Nell'app di esempio viene creato l'endpoint di controllo integrità in /health (BasicStartup.cs):

public class BasicStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHealthChecks();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHealthChecks("/health");
        });
    }
}

Per eseguire lo scenario di configurazione di base usando l'app di esempio, eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario basic

Esempio Docker

Docker offre una direttiva HEALTHCHECK predefinita che può essere usata per controllare lo stato di un'app che usa la configurazione dei controlli di integrità di base:

HEALTHCHECK CMD curl --fail http://localhost:5000/health || exit

Creare controlli di integrità

I controlli di integrità vengono creati implementando l'interfaccia IHealthCheck. Il metodo CheckHealthAsync restituisce HealthCheckResult che indica l'integrità come Healthy, Degraded o Unhealthy. Il risultato viene scritto come risposta di testo non crittografato con un codice di stato configurabile. La configurazione viene descritta nella sezione Opzioni dei controlli di integrità. HealthCheckResult può anche restituire coppie chiave-valore facoltative.

La classe seguente ExampleHealthCheck illustra il layout di un controllo integrità. La logica dei controlli di integrità viene inserita nel CheckHealthAsync metodo . Nell'esempio seguente viene impostata una variabile fittizia, , healthCheckResultHealthysu true. Se il valore di healthCheckResultHealthy è impostato su false, viene restituito lo HealthCheckResult.Unhealthy stato .

public class ExampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var healthCheckResultHealthy = true;

        if (healthCheckResultHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            HealthCheckResult.Unhealthy("An unhealthy result."));
    }
}

Registrare i servizi di controllo dell'integrità

Il ExampleHealthCheck tipo viene aggiunto ai servizi di controllo integrità con AddCheck in Startup.ConfigureServices:

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>("example_health_check");

L'overload AddCheck illustrato nell'esempio seguente imposta lo stato di errore (HealthStatus) per segnalare quando il controllo di integrità indica un errore. Se lo stato di errore è impostato su null (impostazione predefinita), viene segnalato HealthStatus.Unhealthy. Questo overload è uno scenario utile per gli autori di librerie, in cui lo stato di errore indicato dalla libreria viene applicato dall'app quando si verifica un errore di controllo dell'integrità se l'implementazione del controllo dell'integrità rispetta l'impostazione.

Si possono usare tag per filtrare i controlli di integrità, come illustrato più avanti nella sezione Filtrare i controlli di integrità.

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>(
        "example_health_check",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "example" });

AddCheck può anche eseguire una funzione lambda. Nell'esempio seguente il nome del controllo di integrità viene specificato come Example e il controllo restituisce sempre uno stato integro:

services.AddHealthChecks()
    .AddCheck("Example", () =>
        HealthCheckResult.Healthy("Example is OK!"), tags: new[] { "example" });

Chiamare AddTypeActivatedCheck per passare argomenti a un'implementazione del controllo integrità. Nell'esempio seguente accetta TestHealthCheckWithArgs un numero intero e una stringa da usare quando CheckHealthAsync viene chiamato:

private class TestHealthCheckWithArgs : IHealthCheck
{
    public TestHealthCheckWithArgs(int i, string s)
    {
        I = i;
        S = s;
    }

    public int I { get; set; }

    public string S { get; set; }

    public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, 
        CancellationToken cancellationToken = default)
    {
        ...
    }
}

TestHealthCheckWithArgs viene registrato chiamando AddTypeActivatedCheck con l'intero e la stringa passata all'implementazione:

services.AddHealthChecks()
    .AddTypeActivatedCheck<TestHealthCheckWithArgs>(
        "test", 
        failureStatus: HealthStatus.Degraded, 
        tags: new[] { "example" }, 
        args: new object[] { 5, "string" });

Usare il routing dei controlli di integrità

In Startup.Configurechiamare MapHealthChecks sul generatore di endpoint con l'URL dell'endpoint o il percorso relativo:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
});

Richiedi host

Chiamare RequireHost per specificare uno o più host consentiti per l'endpoint di controllo integrità. Gli host devono essere Unicode anziché punycode e possono includere una porta. Se non viene fornita una raccolta, viene accettato qualsiasi host.

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("www.contoso.com:5001");
});

Per altre informazioni, vedere la sezione Filtrare in base alla porta.

Richiedi autorizzazione

Chiamare RequireAuthorization per eseguire il middleware di autorizzazione nell'endpoint della richiesta di controllo integrità. Un RequireAuthorization overload accetta uno o più criteri di autorizzazione. Se non viene specificato un criterio, vengono usati i criteri di autorizzazione predefiniti.

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireAuthorization();
});

Abilitare richieste tra le origini (CORS)

Anche se l'esecuzione manuale dei controlli di integrità da un browser non è uno scenario d'uso comune, il middleware CORS può essere abilitato chiamando RequireCors sugli endpoint dei controlli di integrità. Un RequireCors overload accetta un delegato del generatore di criteri CORS (CorsPolicyBuilder) o un nome di criteri. Se non viene specificato un criterio, viene usato il criterio CORS predefinito. Per altre informazioni, vedere Abilitare le richieste tra le origini (CORS) in ASP.NET Core.

Opzioni dei controlli di integrità

HealthCheckOptions consente di personalizzare il comportamento dei controlli di integrità:

Filtrare i controlli di integrità

Per impostazione predefinita, il middleware dei controlli di integrità esegue tutti i controlli di integrità registrati. Per eseguire un subset dei controlli di integrità, specificare una funzione che restituisce un valore booleano all'opzione Predicate. Nell'esempio seguente il controllo di integrità Bar viene filtrato in base al tag (bar_tag) nell'istruzione condizionale della funzione, dove true viene restituito solo se la proprietà Tags del controllo di integrità corrisponde a foo_tag o a baz_tag:

In Startup.ConfigureServices:

services.AddHealthChecks()
    .AddCheck("Foo", () =>
        HealthCheckResult.Healthy("Foo is OK!"), tags: new[] { "foo_tag" })
    .AddCheck("Bar", () =>
        HealthCheckResult.Unhealthy("Bar is unhealthy!"), tags: new[] { "bar_tag" })
    .AddCheck("Baz", () =>
        HealthCheckResult.Healthy("Baz is OK!"), tags: new[] { "baz_tag" });

In Startup.Configurefiltra Predicate il controllo di integrità "Barra". Solo Foo e Baz execute:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("foo_tag") ||
            check.Tags.Contains("baz_tag")
    });
});

Personalizzare il codice di stato HTTP

Usare ResultStatusCodes per personalizzare il mapping dello stato di integrità dei codici di stato HTTP. Le assegnazioni StatusCodes seguenti sono i valori predefiniti usati dal middleware. Modificare i valori dei codici di stato in base ai requisiti.

In Startup.Configure:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResultStatusCodes =
        {
            [HealthStatus.Healthy] = StatusCodes.Status200OK,
            [HealthStatus.Degraded] = StatusCodes.Status200OK,
            [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
        }
    });
});

Eliminare le intestazioni della cache

AllowCachingResponses controlla se il middleware controlli di integrità aggiunge intestazioni HTTP a una risposta probe per impedire la memorizzazione nella cache delle risposte. Se il valore è false (impostazione predefinita), il middleware imposta le intestazioni Cache-Control, Expires e Pragma o ne esegue l'override per impedire la memorizzazione della risposta nella cache. Se il valore è true, il middleware non modifica le intestazioni della risposta nella cache.

In Startup.Configure:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        AllowCachingResponses = true
    });
});

Personalizzare l'output

In Startup.Configureimpostare l'opzione HealthCheckOptions.ResponseWriter su un delegato per la scrittura della risposta:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
});

Il delegato predefinito scrive una risposta in testo non crittografato minima con il valore di stringa HealthReport.Status. I delegati personalizzati seguenti generano una risposta JSON personalizzata.

Il primo esempio dell'app di esempio illustra come usare System.Text.Json:

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions
    {
        Indented = true
    };

    using (var stream = new MemoryStream())
    {
        using (var writer = new Utf8JsonWriter(stream, options))
        {
            writer.WriteStartObject();
            writer.WriteString("status", result.Status.ToString());
            writer.WriteStartObject("results");
            foreach (var entry in result.Entries)
            {
                writer.WriteStartObject(entry.Key);
                writer.WriteString("status", entry.Value.Status.ToString());
                writer.WriteString("description", entry.Value.Description);
                writer.WriteStartObject("data");
                foreach (var item in entry.Value.Data)
                {
                    writer.WritePropertyName(item.Key);
                    JsonSerializer.Serialize(
                        writer, item.Value, item.Value?.GetType() ??
                        typeof(object));
                }
                writer.WriteEndObject();
                writer.WriteEndObject();
            }
            writer.WriteEndObject();
            writer.WriteEndObject();
        }

        var json = Encoding.UTF8.GetString(stream.ToArray());

        return context.Response.WriteAsync(json);
    }
}

Il secondo esempio illustra come usare Newtonsoft.Json:

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json";

    var json = new JObject(
        new JProperty("status", result.Status.ToString()),
        new JProperty("results", new JObject(result.Entries.Select(pair =>
            new JProperty(pair.Key, new JObject(
                new JProperty("status", pair.Value.Status.ToString()),
                new JProperty("description", pair.Value.Description),
                new JProperty("data", new JObject(pair.Value.Data.Select(
                    p => new JProperty(p.Key, p.Value))))))))));

    return context.Response.WriteAsync(
        json.ToString(Formatting.Indented));
}

Nell'app di esempio impostare come commento la direttiva del SYSTEM_TEXT_JSON preprocessore in CustomWriterStartup.cs per abilitare la Newtonsoft.Json versione di WriteResponse.

L'API dei controlli di integrità non fornisce il supporto predefinito per i formati restituiti JSON complessi perché il formato è specifico della scelta del sistema di monitoraggio. Personalizzare la risposta negli esempi precedenti in base alle esigenze. Per altre informazioni sulla serializzazione JSON con System.Text.Json, vedere Come serializzare e deserializzare JSON in .NET.

Probe del database

Un controllo di integrità può specificare una query di database da eseguire come test booleano per indicare se il database sta rispondendo normalmente.

L'app di esempio usa AspNetCore.Diagnostics.HealthChecks, una libreria di controllo integrità per le app core ASP.NET, per eseguire un controllo integrità in un database di SQL Server. AspNetCore.Diagnostics.HealthChecks esegue una query SELECT 1 sul database per confermare che la connessione al database sia integra.

Avviso

Quando si controlla una connessione di database con una query, scegliere una query che viene restituita rapidamente. Dall'approccio alla query possono derivare il sovraccarico del database e il degrado delle prestazioni. Nella maggior parte dei casi, l'esecuzione di una query di test non è necessaria. È sufficiente stabilire una connessione al database. Se invece è necessario eseguire una query, scegliere una semplice query SELECT, ad esempio SELECT 1.

Includere un riferimento al pacchetto a AspNetCore.HealthChecks.SqlServer.

Specificare un stringa di connessione di database valido nel appsettings.json file dell'app di esempio. L'app usa una database di SQL Server denominato HealthCheckSample:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=HealthCheckSample;Trusted_Connection=True;MultipleActiveResultSets=true;ConnectRetryCount=0"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "Console": {
      "IncludeScopes": "true"
    }
  },
  "AllowedHosts": "*"
}

Registrare i servizi dei controlli di integrità con AddHealthChecks in Startup.ConfigureServices. L'app di esempio chiama il AddSqlServer metodo con il stringa di connessione del database (DbHealthStartup.cs):

services.AddHealthChecks()
    .AddSqlServer(Configuration["ConnectionStrings:DefaultConnection"]);

Un endpoint di controllo dell'integrità viene creato chiamando MapHealthChecks in Startup.Configure:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

Per eseguire lo scenario di probe del database di base usando l'app di esempio, eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario db

Nota

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Probe DbContext di Entity Framework Core

Il DbContext controllo conferma che l'app può comunicare con il database configurato per un oggetto EF CoreDbContext. Il controllo DbContext è supportato nelle app che:

AddDbContextCheck<TContext> registra un controllo di integrità per un DbContext. DbContext viene reso disponibile come TContext al metodo. È disponibile un overload per configurare lo stato di errore, i tag e una query di test personalizzata.

Per impostazione predefinita:

  • Il DbContextHealthCheck metodo chiama EF Coreil metodo .CanConnectAsync È possibile determinare l'operazione da eseguire quando si controlla l'integrità usando gli overload del metodo AddDbContextCheck.
  • Il nome del controllo di integrità è il nome del tipo TContext.

Nell'app di esempio viene AppDbContext fornito AddDbContextCheck e registrato come servizio in Startup.ConfigureServices (DbContextHealthStartup.cs):

services.AddHealthChecks()
    .AddDbContextCheck<AppDbContext>();

services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(
        Configuration["ConnectionStrings:DefaultConnection"]);
});

Un endpoint di controllo dell'integrità viene creato chiamando MapHealthChecks in Startup.Configure:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

Per eseguire lo scenario di probe DbContext usando l'app di esempio, verificare che il database specificato dalla stringa di connessione non esista nell'istanza di SQL Server. Se il database esiste, eliminarlo.

Eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario dbcontext

Dopo che l'app è in esecuzione, controllare lo stato di integrità effettuando una richiesta all'endpoint /health in un browser. Il database e AppDbContext non esistono, quindi l'app fornisce la risposta seguente:

Unhealthy

Attivare l'app di esempio per creare il database. Effettuare una richiesta a /createdatabase. L'app risponde:

Creating the database...
Done!
Navigate to /health to see the health status.

Effettuare una richiesta all'endpoint /health. Il database e il contesto esistono, quindi l'app risponde:

Healthy

Attivare l'app di esempio per eliminare il database. Effettuare una richiesta a /deletedatabase. L'app risponde:

Deleting the database...
Done!
Navigate to /health to see the health status.

Effettuare una richiesta all'endpoint /health. L'app fornisce una risposta non integra:

Unhealthy

Separare i probe di idoneità e di attività

In alcuni scenari di hosting viene usata una coppia di controlli di integrità per distinguere due stati dell'app:

  • Idoneità indica se l'app è in esecuzione normalmente, ma non è pronta per ricevere le richieste.
  • Liveness indica se un'app si è arrestata in modo anomalo e deve essere riavviata.

Si consideri l'esempio seguente: un'app deve scaricare un file di configurazione di grandi dimensioni prima che sia pronto per elaborare le richieste. Non si vuole riavviare l'app se il download iniziale non riesce perché l'app può riprovare a scaricare il file più volte. Viene usato un probe di attività per descrivere la durata del processo, non vengono eseguiti altri controlli. Si vuole anche impedire che le richieste vengano inviate all'app prima che il download del file di configurazione abbia avuto esito positivo. Usiamo un probe di idoneità per indicare uno stato "non pronto" fino a quando il download non riesce e l'app è pronta per ricevere le richieste.

L'app di esempio contiene un controllo di integrità per segnalare il completamento dell'attività di avvio con esecuzione prolungata in un servizio ospitato. StartupHostedServiceHealthCheck espone una proprietà , StartupTaskCompleted, su cui il servizio ospitato può essere impostato true al termine dell'attività a esecuzione prolungata (StartupHostedServiceHealthCheck.cs):

public class StartupHostedServiceHealthCheck : IHealthCheck
{
    private volatile bool _startupTaskCompleted = false;

    public string Name => "slow_dependency_check";

    public bool StartupTaskCompleted
    {
        get => _startupTaskCompleted;
        set => _startupTaskCompleted = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        if (StartupTaskCompleted)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("The startup task is finished."));
        }

        return Task.FromResult(
            HealthCheckResult.Unhealthy("The startup task is still running."));
    }
}

L'attività in background a esecuzione prolungata viene avviata da un servizio ospitato (Services/StartupHostedService). Al termine dell'attività, StartupHostedServiceHealthCheck.StartupTaskCompleted viene impostata su true:

public class StartupHostedService : IHostedService, IDisposable
{
    private readonly int _delaySeconds = 15;
    private readonly ILogger _logger;
    private readonly StartupHostedServiceHealthCheck _startupHostedServiceHealthCheck;

    public StartupHostedService(ILogger<StartupHostedService> logger,
        StartupHostedServiceHealthCheck startupHostedServiceHealthCheck)
    {
        _logger = logger;
        _startupHostedServiceHealthCheck = startupHostedServiceHealthCheck;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is starting.");

        // Simulate the effect of a long-running startup task.
        Task.Run(async () =>
        {
            await Task.Delay(_delaySeconds * 1000);

            _startupHostedServiceHealthCheck.StartupTaskCompleted = true;

            _logger.LogInformation("Startup Background Service has started.");
        });

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is stopping.");

        return Task.CompletedTask;
    }

    public void Dispose()
    {
    }
}

Il controllo di integrità viene registrato con AddCheck in Startup.ConfigureServices insieme al servizio ospitato. Poiché il servizio ospitato deve impostare la proprietà nel controllo integrità, il controllo integrità viene registrato anche nel contenitore del servizio (LivenessProbeStartup.cs):

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

Un endpoint di controllo dell'integrità viene creato chiamando MapHealthChecks in Startup.Configure. Nell'app di esempio gli endpoint di controllo integrità vengono creati in:

  • /health/ready per il controllo di conformità. Il controllo di idoneità filtra i controlli di integrità per il controllo di integrità con il tag ready.
  • /health/live per il controllo del liveness. Il controllo attività filtra l'oggetto StartupHostedServiceHealthCheck restituendo false in HealthCheckOptions.Predicate (per altre informazioni, vedere Filtrare i controlli di integrità)

Nel codice di esempio seguente:

  • Il controllo di conformità usa tutti i controlli registrati con il tag 'ready'.
  • Predicate Esclude tutti i controlli e restituisce un valore 200-Ok.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

Per eseguire lo scenario di configurazione di idoneità/attività usando l'app di esempio, eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario liveness

In a browser visitare più volte /health/ready per 15 secondi. Il controllo di integrità segnala Unhealthy per i primi 15 secondi. Dopo 15 secondi, l'endpoint segnala Healthy, che indica il completamento dell'attività con esecuzione prolungata da parte del servizio ospitato.

Questo esempio crea anche un server di pubblicazione controllo integrità (IHealthCheckPublisher implementazione) che esegue il primo controllo di idoneità con un ritardo di due secondi. Per altre informazioni, vedere la sezione Server di pubblicazione dei controlli di integrità.

Esempio di Kubernetes

L'uso di controlli di idoneità e attività separati è utile in un ambiente come Kubernetes. In Kubernetes potrebbe essere necessaria un'app per eseguire operazioni di avvio che richiedono molto tempo prima di accettare richieste, ad esempio un test della disponibilità del database sottostante. L'uso di controlli separati consente all'agente di orchestrazione di distinguere se l'app è funzionante, ma non è ancora pronta o se l'app non è stata avviata. Per altre informazioni sui probe di idoneità e di attività in Kubernetes, vedere Configure Liveness and Readiness Probes (Configurare i probe di attività e di idoneità in Kubernetes) nella documentazione di Kubernetes.

L'esempio seguente illustra la configurazione di un probe di idoneità di Kubernetes:

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /health/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

Probe basato sulle metriche con un writer di risposta personalizzata

L'app di esempio illustra un controllo di integrità della memoria con un writer di risposta personalizzata.

MemoryHealthCheck segnala uno stato danneggiato se l'app usa più di una determinata soglia di memoria (1 GB nell'app di esempio). HealthCheckResult Include le informazioni di Garbage Collector (GC) per l'app (MemoryHealthCheck.cs):

public class MemoryHealthCheck : IHealthCheck
{
    private readonly IOptionsMonitor<MemoryCheckOptions> _options;

    public MemoryHealthCheck(IOptionsMonitor<MemoryCheckOptions> options)
    {
        _options = options;
    }

    public string Name => "memory_check";

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var options = _options.Get(context.Registration.Name);

        // Include GC information in the reported diagnostics.
        var allocated = GC.GetTotalMemory(forceFullCollection: false);
        var data = new Dictionary<string, object>()
        {
            { "AllocatedBytes", allocated },
            { "Gen0Collections", GC.CollectionCount(0) },
            { "Gen1Collections", GC.CollectionCount(1) },
            { "Gen2Collections", GC.CollectionCount(2) },
        };
        var status = (allocated < options.Threshold) ?
            HealthStatus.Healthy : context.Registration.FailureStatus;

        return Task.FromResult(new HealthCheckResult(
            status,
            description: "Reports degraded status if allocated bytes " +
                $">= {options.Threshold} bytes.",
            exception: null,
            data: data));
    }
}

Registrare i servizi dei controlli di integrità con AddHealthChecks in Startup.ConfigureServices. Invece di abilitare il controllo di integrità passandolo ad AddCheck, MemoryHealthCheck viene registrato come servizio. Tutti i servizi registrati da IHealthCheck sono disponibili per il middleware e i servizi di controllo dell'integrità. È consigliabile registrare i servizi di controllo dell'integrità come servizi Singleton.

Nell'app CustomWriterStartup.cs di esempio:

services.AddHealthChecks()
    .AddMemoryHealthCheck("memory");

Un endpoint di controllo dell'integrità viene creato chiamando MapHealthChecks in Startup.Configure. Viene fornito un delegato WriteResponse alla proprietà ResponseWriter per visualizzare una risposta JSON personalizzata quando il controllo di integrità viene eseguito:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
}

Il WriteResponse delegato formatta l'oggetto CompositeHealthCheckResult in un oggetto JSON e restituisce l'output JSON per la risposta al controllo integrità. Per altre informazioni, vedere la sezione Personalizzare l'output.

Per eseguire lo scenario di probe basato sulle metriche con il writer di risposta personalizzata usando l'app di esempio, eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario writer

Nota

AspNetCore.Diagnostics.HealthChecks include scenari di controllo dell'integrità basato su metriche, tra cui l'archiviazione su disco e i controlli di livezza dei valori massimi.

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Filtrare in base alla porta

MapHealthChecks Chiamare RequireHost con un modello di URL che specifica una porta per limitare le richieste di controllo integrità alla porta specificata. Questo approccio viene in genere usato in un ambiente contenitore per esporre una porta per i servizi di monitoraggio.

L'app di esempio configura la porta usando il provider di configurazione della variabile di ambiente. La porta viene impostata nel launchSettings.json file e passata al provider di configurazione tramite una variabile di ambiente. È anche necessario configurare il server per l'ascolto di richieste sulla porta di gestione.

Per usare l'app di esempio per illustrare la configurazione delle porte di gestione, creare il launchSettings.json file in una Properties cartella.

Il file seguente Properties/launchSettings.json nell'app di esempio non è incluso nei file di progetto dell'app di esempio e deve essere creato manualmente:

{
  "profiles": {
    "SampleApp": {
      "commandName": "Project",
      "commandLineArgs": "",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_URLS": "http://localhost:5000/;http://localhost:5001/",
        "ASPNETCORE_MANAGEMENTPORT": "5001"
      },
      "applicationUrl": "http://localhost:5000/"
    }
  }
}

Registrare i servizi dei controlli di integrità con AddHealthChecks in Startup.ConfigureServices. Creare un endpoint di controllo dell'integrità chiamando MapHealthChecks in Startup.Configure.

Nell'app di esempio, una chiamata a RequireHost sull'endpoint in Startup.Configure specifica la porta di gestione dalla configurazione:

endpoints.MapHealthChecks("/health")
    .RequireHost($"*:{Configuration["ManagementPort"]}");

Gli endpoint vengono creati nell'app di esempio in Startup.Configure. Nel codice di esempio seguente:

  • Il controllo di conformità usa tutti i controlli registrati con il tag 'ready'.
  • Predicate Esclude tutti i controlli e restituisce un valore 200-Ok.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

Nota

È possibile evitare di creare il launchSettings.json file nell'app di esempio impostando la porta di gestione in modo esplicito nel codice. In Program.cs cui viene creato , HostBuilder aggiungere una chiamata a ListenAnyIP e fornire l'endpoint della porta di gestione dell'app. In Configure specificare la porta di ManagementPortStartup.csgestione con RequireHost:

Program.cs:

return new HostBuilder()
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseKestrel()
            .ConfigureKestrel(serverOptions =>
            {
                serverOptions.ListenAnyIP(5001);
            })
            .UseStartup(startupType);
    })
    .Build();

ManagementPortStartup.cs:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("*:5001");
});

Per eseguire lo scenario di configurazione della porta di gestione usando l'app di esempio, eseguire il comando seguente dalla cartella del progetto in una shell dei comandi:

dotnet run --scenario port

Distribuire una libreria di controllo di integrità

Per distribuire un controllo di integrità come libreria:

  1. Scrivere un controllo di integrità che implementa l'interfaccia IHealthCheck come classe autonoma. La classe può basarsi su inserimento delle dipendenze, attivazione del tipo e opzioni denominate per accedere ai dati di configurazione.

    Nella logica dei controlli di integrità di CheckHealthAsync:

    • data1 e data2 vengono usati nel metodo per eseguire la logica del controllo di integrità del probe.
    • AccessViolationException viene gestito.

    Quando si verifica un oggetto AccessViolationException , viene FailureStatus restituito con per HealthCheckResult consentire agli utenti di configurare lo stato di errore dei controlli di integrità.

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    namespace SampleApp
    {
        public class ExampleHealthCheck : IHealthCheck
        {
            private readonly string _data1;
            private readonly int? _data2;
    
            public ExampleHealthCheck(string data1, int? data2)
            {
                _data1 = data1 ?? throw new ArgumentNullException(nameof(data1));
                _data2 = data2 ?? throw new ArgumentNullException(nameof(data2));
            }
    
            public async Task<HealthCheckResult> CheckHealthAsync(
                HealthCheckContext context, CancellationToken cancellationToken)
            {
                try
                {
                    return HealthCheckResult.Healthy();
                }
                catch (AccessViolationException ex)
                {
                    return new HealthCheckResult(
                        context.Registration.FailureStatus,
                        description: "An access violation occurred during the check.",
                        exception: ex,
                        data: null);
                }
            }
        }
    }
    
  2. Scrivere un metodo di estensione con i parametri che l'app chiama nel metodo Startup.Configure. Nell'esempio seguente si presuma la firma del metodo di controllo dell'integrità seguente:

    ExampleHealthCheck(string, string, int )
    

    La firma precedente indica che ExampleHealthCheck richiede dati aggiuntivi per elaborare la logica del probe di controllo dell'integrità. I dati vengono forniti al delegato usato per creare l'istanza del controllo di integrità quando il controllo di integrità viene registrato con un metodo di estensione. Nell'esempio seguente il chiamante specifica facoltativamente:

    • nome del controllo integrità (name). Se null, viene usato example_health_check.
    • punto dati stringa per il controllo di integrità (data1).
    • punto dati Integer per il controllo di integrità (data2). Se null, viene usato 1.
    • stato dell'errore (HealthStatus). Il valore predefinito è null. Se null, viene segnalato HealthStatus.Unhealthy come stato di errore.
    • tag (IEnumerable<string>).
    using System.Collections.Generic;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    public static class ExampleHealthCheckBuilderExtensions
    {
        const string DefaultName = "example_health_check";
    
        public static IHealthChecksBuilder AddExampleHealthCheck(
            this IHealthChecksBuilder builder,
            string name = default,
            string data1,
            int data2 = 1,
            HealthStatus? failureStatus = default,
            IEnumerable<string> tags = default)
        {
            return builder.Add(new HealthCheckRegistration(
                name ?? DefaultName,
                sp => new ExampleHealthCheck(data1, data2),
                failureStatus,
                tags));
        }
    }
    

Server di pubblicazione dei controlli di integrità

Quando IHealthCheckPublisher viene aggiunto al contenitore del servizio, il sistema di controllo dell'integrità esegue periodicamente i controlli di integrità e chiama PublishAsync con il risultato. Ciò è utile in uno scenario relativo a un sistema di monitoraggio dell'integrità basato su push, che prevede che ogni processo chiami periodicamente il sistema di monitoraggio per determinare l'integrità.

L'interfaccia IHealthCheckPublisher ha un solo metodo:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions consente di impostare:

  • Delay: ritardo iniziale applicato dopo l'avvio dell'app prima dell'esecuzione delle IHealthCheckPublisher istanze. Il ritardo viene applicato una sola volta all'avvio e non si applica alle iterazioni successive. Il valore predefinito è cinque secondi.
  • Period: periodo di IHealthCheckPublisher esecuzione. Il valore predefinito è 30 secondi.
  • Predicate: se Predicate è null (impostazione predefinita), il servizio di pubblicazione controllo integrità esegue tutti i controlli di integrità registrati. Per eseguire un subset dei controlli di integrità, specificare una funzione che filtra il set di controlli. Il predicato viene valutato per ogni periodo.
  • Timeout: timeout per l'esecuzione dei controlli di integrità per tutte le IHealthCheckPublisher istanze. Usare InfiniteTimeSpan per l'esecuzione senza un timeout. Il valore predefinito è 30 secondi.

Nell'app di esempio, ReadinessPublisher è un'implementazione di IHealthCheckPublisher. Lo stato del controllo integrità viene registrato per ogni controllo a livello di log di:

public class ReadinessPublisher : IHealthCheckPublisher
{
    private readonly ILogger _logger;

    public ReadinessPublisher(ILogger<ReadinessPublisher> logger)
    {
        _logger = logger;
    }

    // The following example is for demonstration purposes only. Health Checks
    // Middleware already logs health checks results. A real-world readiness
    // check in a production app might perform a set of more expensive or
    // time-consuming checks to determine if other resources are responding
    // properly.
    public Task PublishAsync(HealthReport report,
        CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            _logger.LogInformation("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }
        else
        {
            _logger.LogError("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }

        cancellationToken.ThrowIfCancellationRequested();

        return Task.CompletedTask;
    }
}

Nell'esempio di LivenessProbeStartup dell'app di esempio, il controllo di conformità StartupHostedService ha un ritardo di avvio di due secondi e il controllo viene eseguito ogni 30 secondi. Per attivare l'implementazione IHealthCheckPublisher, l'esempio registra ReadinessPublisher come servizio singleton nel contenitore di inserimento delle dipendenze:

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

Nota

AspNetCore.Diagnostics.HealthChecks include editori per diversi sistemi, tra cui Application Insights.

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Limitare i controlli integrità con MapWhen

Usare MapWhen per creare un ramo condizionale della pipeline delle richieste per gli endpoint di controllo integrità.

Nell'esempio seguente la MapWhen pipeline di richiesta viene inramata per attivare il middleware di controlli di integrità se viene ricevuta una richiesta GET per l'endpoint api/HealthCheck :

app.MapWhen(
    context => context.Request.Method == HttpMethod.Get.Method && 
        context.Request.Path.StartsWith("/api/HealthCheck"),
    builder => builder.UseHealthChecks());

app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
});

Per altre informazioni, vedere Middleware ASP.NET Core.

ASP.NET Core offre il middleware e le librerie di controlli di integrità per segnalare l'integrità dei componenti dell'infrastruttura delle app.

I controlli di integrità vengono esposti da un'app come endpoint HTTP. Gli endpoint di controllo integrità possono essere configurati per vari scenari di monitoraggio in tempo reale:

  • I probe di integrità possono essere usati dagli agenti di orchestrazione e dai servizi di bilanciamento del carico per controllare lo stato di un'app. Ad esempio, un agente di orchestrazione potrebbe rispondere a controllo di integrità non superato arrestando una distribuzione in sequenza o riavviando un contenitore. Un servizio di bilanciamento del carico potrebbe reagire a un'app non integra trasferendo il traffico dall'istanza con errori a un'istanza integra.
  • È possibile monitorare lo stato di integrità di memoria, disco e altre risorse fisiche del server.
  • I controlli di integrità possono testare le dipendenze di un'app, ad esempio i database e gli endpoint di servizio esterni, per verificare la disponibilità e il normale funzionamento.

I controlli di integrità vengono in genere usati con un servizio di monitoraggio esterno o un agente di orchestrazione del contenitore per controllare lo stato di un'app. Prima di aggiungere i controlli di integrità a un'app, decidere quale sistema di monitoraggio usare. Il sistema di monitoraggio determina quali tipi di controlli di integrità creare e come configurare i relativi endpoint.

Probe di integrità di base

Per molte app, una configurazione del probe di integrità di base, che segnala la disponibilità dell'app per elaborare le richieste (attività), è sufficiente per individuare lo stato dell'app.

La configurazione di base registra i servizi di controllo integrità e chiama il middleware controlli di integrità per rispondere a un endpoint URL con una risposta di integrità. Per impostazione predefinita, non vengono registrati controlli di integrità specifici per testare particolari dipendenze o sottosistemi. L'app viene considerata integra se può rispondere all'URL dell'endpoint di integrità. Il writer di risposta predefinito scrive HealthStatus come risposta in testo non crittografato al client. è HealthStatus HealthStatus.Healthy, HealthStatus.Degradedo HealthStatus.Unhealthy.

Registrare i servizi dei controlli di integrità con AddHealthChecks in Program.cs. Creare un endpoint di controllo dell'integrità chiamando MapHealthChecks.

L'esempio seguente crea un endpoint di controllo integrità in /healthz:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

Docker offre una direttiva HEALTHCHECK predefinita che può essere usata per controllare lo stato di un'app che usa la configurazione dei controlli di integrità di base:

HEALTHCHECK CMD curl --fail http://localhost:5000/healthz || exit

Nell'esempio precedente viene curl usato per effettuare una richiesta HTTP all'endpoint del controllo integrità in /healthz. curl non è incluso nelle immagini del contenitore .NET Linux, ma può essere aggiunto installando il pacchetto necessario nel Dockerfile. I contenitori che usano immagini basate su Alpine Linux possono usare l'oggetto incluso wget al posto di curl.

Creare controlli di integrità

I controlli di integrità vengono creati implementando l'interfaccia IHealthCheck. Il metodo CheckHealthAsync restituisce HealthCheckResult che indica l'integrità come Healthy, Degraded o Unhealthy. Il risultato viene scritto come risposta in testo non crittografato con un codice di stato configurabile. La configurazione è descritta nella sezione Opzioni controllo integrità. HealthCheckResult può anche restituire coppie chiave-valore facoltative.

Nell'esempio seguente viene illustrato il layout di un controllo integrità:

public class SampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

La logica del controllo integrità viene inserita nel CheckHealthAsync metodo . Nell'esempio precedente viene impostata una variabile fittizia, , isHealthysu true. Se il valore di isHealthy è impostato su false, viene restituito lo HealthCheckRegistration.FailureStatus stato .

Se CheckHealthAsync genera un'eccezione durante il controllo, viene restituito un nuovo HealthReportEntry oggetto con il relativo HealthReportEntry.Status set su FailureStatus. Questo stato è definito da AddCheck (vedere la sezione Registrare i servizi di controllo integrità) e include l'eccezione interna che ha causato l'errore di controllo. l'oggetto Description è impostato sul messaggio dell'eccezione.

Registrare i servizi di controllo dell'integrità

Per registrare un servizio di controllo integrità, chiamare AddCheck in Program.cs:

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>("Sample");

L'overload AddCheck illustrato nell'esempio seguente imposta lo stato di errore (HealthStatus) per segnalare quando il controllo di integrità indica un errore. Se lo stato di errore è impostato su null (impostazione predefinita), viene segnalato HealthStatus.Unhealthy. Questo overload è uno scenario utile per gli autori di librerie, in cui lo stato di errore indicato dalla libreria viene applicato dall'app quando si verifica un errore di controllo dell'integrità se l'implementazione del controllo dell'integrità rispetta l'impostazione.

I tag possono essere usati per filtrare i controlli di integrità. I tag sono descritti nella sezione Filtri controlli di integrità.

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" });

AddCheck può anche eseguire una funzione lambda. Nell'esempio seguente il controllo integrità restituisce sempre un risultato integro:

builder.Services.AddHealthChecks()
    .AddCheck("Sample", () => HealthCheckResult.Healthy("A healthy result."));

Chiamare AddTypeActivatedCheck per passare argomenti a un'implementazione del controllo integrità. Nell'esempio seguente un controllo di integrità attivato dal tipo accetta un numero intero e una stringa nel relativo costruttore:

public class SampleHealthCheckWithArgs : IHealthCheck
{
    private readonly int _arg1;
    private readonly string _arg2;

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        // ...

        return Task.FromResult(HealthCheckResult.Healthy("A healthy result."));
    }
}

Per registrare il controllo integrità precedente, chiamare AddTypeActivatedCheck con l'intero e la stringa passati come argomenti:

builder.Services.AddHealthChecks()
    .AddTypeActivatedCheck<SampleHealthCheckWithArgs>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" },
        args: new object[] { 1, "Arg" });

Usare il routing dei controlli di integrità

In Program.cschiamare MapHealthChecks sul generatore di endpoint con l'URL dell'endpoint o il percorso relativo:

app.MapHealthChecks("/healthz");

Richiedi host

Chiamare RequireHost per specificare uno o più host consentiti per l'endpoint di controllo integrità. Gli host devono essere Unicode anziché punycode e possono includere una porta. Se non viene fornita una raccolta, viene accettato qualsiasi host:

app.MapHealthChecks("/healthz")
    .RequireHost("www.contoso.com:5001");

Per limitare la risposta dell'endpoint del controllo integrità solo su una porta specifica, specificare una porta nella chiamata a RequireHost. Questo approccio viene in genere usato in un ambiente contenitore per esporre una porta per i servizi di monitoraggio:

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001");

Avviso

L'API che si basa sull'intestazione Host, ad esempio HttpRequest.Host e RequireHost, è soggetta a potenziali spoofing da parte dei client.

Per evitare lo spoofing di host e porta, usare uno degli approcci seguenti:

Per impedire ai client non autorizzati di eseguire lo spoofing della porta, chiamare RequireAuthorization:

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001")
    .RequireAuthorization();

Per altre informazioni, vedere Corrispondenza host nelle route con RequireHost.

Richiedi autorizzazione

Chiamare RequireAuthorization per eseguire il middleware di autorizzazione nell'endpoint della richiesta di controllo integrità. Un RequireAuthorization overload accetta uno o più criteri di autorizzazione. Se non viene specificato un criterio, vengono usati i criteri di autorizzazione predefiniti:

app.MapHealthChecks("/healthz")
    .RequireAuthorization();

Abilitare richieste tra le origini (CORS)

Anche se l'esecuzione manuale dei controlli di integrità da un browser non è uno scenario comune, il middleware CORS può essere abilitato chiamando RequireCors gli endpoint dei controlli di integrità. L'overload RequireCors accetta un delegato del generatore di criteri CORS (CorsPolicyBuilder) o un nome di criteri. Per altre informazioni, vedere Abilitare le richieste tra le origini (CORS) in ASP.NET Core.

Opzioni dei controlli di integrità

HealthCheckOptions consente di personalizzare il comportamento dei controlli di integrità:

Filtrare i controlli di integrità

Per impostazione predefinita, il middleware controlli di integrità esegue tutti i controlli di integrità registrati. Per eseguire un subset dei controlli di integrità, specificare una funzione che restituisce un valore booleano all'opzione Predicate.

Nell'esempio seguente vengono filtrati i controlli di integrità in modo che solo quelli contrassegnati con l'esecuzione sample :

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("sample")
});

Personalizzare il codice di stato HTTP

Usare ResultStatusCodes per personalizzare il mapping dello stato di integrità dei codici di stato HTTP. Le assegnazioni StatusCodes seguenti sono i valori predefiniti usati dal middleware. Modificare i valori del codice di stato per soddisfare i requisiti:

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResultStatusCodes =
    {
        [HealthStatus.Healthy] = StatusCodes.Status200OK,
        [HealthStatus.Degraded] = StatusCodes.Status200OK,
        [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
    }
});

Eliminare le intestazioni della cache

AllowCachingResponses controlla se il middleware controlli di integrità aggiunge intestazioni HTTP a una risposta probe per impedire la memorizzazione nella cache delle risposte. Se il valore è false (impostazione predefinita), il middleware imposta le intestazioni Cache-Control, Expires e Pragma o ne esegue l'override per impedire la memorizzazione della risposta nella cache. Se il valore è true, il middleware non modifica le intestazioni della cache della risposta:

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    AllowCachingResponses = true
});

Personalizzare l'output

Per personalizzare l'output di un report dei controlli di integrità, impostare la HealthCheckOptions.ResponseWriter proprietà su un delegato che scrive la risposta:

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResponseWriter = WriteResponse
});

Il delegato predefinito scrive una risposta in testo non crittografato minima con il valore di stringa HealthReport.Status. Il delegato personalizzato seguente restituisce una risposta JSON personalizzata usando System.Text.Json:

private static Task WriteResponse(HttpContext context, HealthReport healthReport)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions { Indented = true };

    using var memoryStream = new MemoryStream();
    using (var jsonWriter = new Utf8JsonWriter(memoryStream, options))
    {
        jsonWriter.WriteStartObject();
        jsonWriter.WriteString("status", healthReport.Status.ToString());
        jsonWriter.WriteStartObject("results");

        foreach (var healthReportEntry in healthReport.Entries)
        {
            jsonWriter.WriteStartObject(healthReportEntry.Key);
            jsonWriter.WriteString("status",
                healthReportEntry.Value.Status.ToString());
            jsonWriter.WriteString("description",
                healthReportEntry.Value.Description);
            jsonWriter.WriteStartObject("data");

            foreach (var item in healthReportEntry.Value.Data)
            {
                jsonWriter.WritePropertyName(item.Key);

                JsonSerializer.Serialize(jsonWriter, item.Value,
                    item.Value?.GetType() ?? typeof(object));
            }

            jsonWriter.WriteEndObject();
            jsonWriter.WriteEndObject();
        }

        jsonWriter.WriteEndObject();
        jsonWriter.WriteEndObject();
    }

    return context.Response.WriteAsync(
        Encoding.UTF8.GetString(memoryStream.ToArray()));
}

L'API dei controlli di integrità non fornisce il supporto predefinito per i formati restituiti JSON complessi perché il formato è specifico della scelta del sistema di monitoraggio. Personalizzare la risposta negli esempi precedenti in base alle esigenze. Per altre informazioni sulla serializzazione JSON con System.Text.Json, vedere Come serializzare e deserializzare JSON in .NET.

Probe del database

Un controllo di integrità può specificare una query di database da eseguire come test booleano per indicare se il database sta rispondendo normalmente.

AspNetCore.Diagnostics.HealthChecks, una libreria di controllo dell'integrità per le app core ASP.NET, include un controllo integrità eseguito su un database di SQL Server. AspNetCore.Diagnostics.HealthChecks esegue una query SELECT 1 sul database per confermare che la connessione al database sia integra.

Avviso

Quando si controlla una connessione di database con una query, scegliere una query che viene restituita rapidamente. Dall'approccio alla query possono derivare il sovraccarico del database e il degrado delle prestazioni. Nella maggior parte dei casi, l'esecuzione di una query di test non è necessaria. È sufficiente stabilire una connessione al database. Se invece è necessario eseguire una query, scegliere una semplice query SELECT, ad esempio SELECT 1.

Per usare questo controllo integrità di SQL Server, includere un riferimento al AspNetCore.HealthChecks.SqlServer pacchetto NuGet. Nell'esempio seguente viene registrato il controllo integrità di SQL Server:

builder.Services.AddHealthChecks()
    .AddSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection"));

Nota

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Probe DbContext di Entity Framework Core

Il DbContext controllo conferma che l'app può comunicare con il database configurato per un oggetto EF CoreDbContext. Il controllo DbContext è supportato nelle app che:

AddDbContextCheck registra un controllo di integrità per un DbContext. L'oggetto DbContext viene fornito al metodo come TContext. È disponibile un overload per configurare lo stato di errore, i tag e una query di test personalizzata.

Per impostazione predefinita:

  • Il DbContextHealthCheck metodo chiama EF Coreil metodo .CanConnectAsync È possibile determinare l'operazione da eseguire quando si controlla l'integrità usando gli overload del metodo AddDbContextCheck.
  • Il nome del controllo di integrità è il nome del tipo TContext.

Nell'esempio seguente viene registrato un DbContext oggetto e un oggetto associato DbContextHealthCheck:

builder.Services.AddDbContext<SampleDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddHealthChecks()
    .AddDbContextCheck<SampleDbContext>();

Separare i probe di idoneità e di attività

In alcuni scenari di hosting viene usata una coppia di controlli di integrità per distinguere due stati dell'app:

  • Idoneità indica se l'app è in esecuzione normalmente, ma non è pronta per ricevere le richieste.
  • Liveness indica se un'app si è arrestata in modo anomalo e deve essere riavviata.

Si consideri l'esempio seguente: un'app deve scaricare un file di configurazione di grandi dimensioni prima che sia pronto per elaborare le richieste. Non si vuole riavviare l'app se il download iniziale non riesce perché l'app può riprovare a scaricare il file più volte. Viene usato un probe di attività per descrivere la durata del processo, non vengono eseguiti altri controlli. Si vuole anche impedire che le richieste vengano inviate all'app prima che il download del file di configurazione abbia avuto esito positivo. Usiamo un probe di idoneità per indicare uno stato "non pronto" fino a quando il download non riesce e l'app è pronta per ricevere le richieste.

L'attività in background seguente simula un processo di avvio che richiede circa 15 secondi. Al termine, l'attività imposta la StartupHealthCheck.StartupCompleted proprietà su true:

public class StartupBackgroundService : BackgroundService
{
    private readonly StartupHealthCheck _healthCheck;

    public StartupBackgroundService(StartupHealthCheck healthCheck)
        => _healthCheck = healthCheck;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Simulate the effect of a long-running task.
        await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);

        _healthCheck.StartupCompleted = true;
    }
}

Segnala StartupHealthCheck il completamento dell'attività di avvio a esecuzione prolungata ed espone la StartupCompleted proprietà che viene impostata dal servizio in background:

public class StartupHealthCheck : IHealthCheck
{
    private volatile bool _isReady;

    public bool StartupCompleted
    {
        get => _isReady;
        set => _isReady = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        if (StartupCompleted)
        {
            return Task.FromResult(HealthCheckResult.Healthy("The startup task has completed."));
        }

        return Task.FromResult(HealthCheckResult.Unhealthy("That startup task is still running."));
    }
}

Il controllo di integrità viene registrato con AddCheck in Program.cs insieme al servizio ospitato. Poiché il servizio ospitato deve impostare la proprietà nel controllo integrità, il controllo integrità viene registrato anche nel contenitore del servizio come singleton:

builder.Services.AddHostedService<StartupBackgroundService>();
builder.Services.AddSingleton<StartupHealthCheck>();

builder.Services.AddHealthChecks()
    .AddCheck<StartupHealthCheck>(
        "Startup",
        tags: new[] { "ready" });

Per creare due endpoint di controllo integrità diversi, chiamare MapHealthChecks due volte:

app.MapHealthChecks("/healthz/ready", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("ready")
});

app.MapHealthChecks("/healthz/live", new HealthCheckOptions
{
    Predicate = _ => false
});

L'esempio precedente crea gli endpoint di controllo integrità seguenti:

  • /healthz/ready per il controllo di conformità. Il controllo di conformità filtra i controlli di integrità a quelli contrassegnati con ready.
  • /healthz/live per il controllo del liveness. Il controllo attività filtra tutti i controlli di integrità restituendo false nel HealthCheckOptions.Predicate delegato. Per altre informazioni sul filtro dei controlli di integrità, vedere Filtrare i controlli di integrità in questo articolo.

Prima del completamento dell'attività di avvio, l'endpoint /healthz/ready segnala uno Unhealthy stato. Al termine dell'attività di avvio, questo endpoint segnala uno Healthy stato. L'endpoint /healthz/live esclude tutti i controlli e segnala uno Healthy stato per tutte le chiamate.

Esempio di Kubernetes

L'uso di controlli di idoneità e attività separati è utile in un ambiente come Kubernetes. In Kubernetes potrebbe essere necessaria un'app per eseguire operazioni di avvio che richiedono molto tempo prima di accettare richieste, ad esempio un test della disponibilità del database sottostante. L'uso di controlli separati consente all'agente di orchestrazione di distinguere se l'app è funzionante, ma non è ancora pronta o se l'app non è stata avviata. Per altre informazioni sui probe di idoneità e di attività in Kubernetes, vedere Configure Liveness and Readiness Probes (Configurare i probe di attività e di idoneità in Kubernetes) nella documentazione di Kubernetes.

L'esempio seguente illustra la configurazione di un probe di idoneità di Kubernetes:

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /healthz/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

Distribuire una libreria di controllo di integrità

Per distribuire un controllo di integrità come libreria:

  1. Scrivere un controllo di integrità che implementa l'interfaccia IHealthCheck come classe autonoma. La classe può basarsi su inserimento delle dipendenze, attivazione del tipo e opzioni denominate per accedere ai dati di configurazione.

  2. Scrivere un metodo di estensione con i parametri che l'app chiama nel metodo Program.cs. Si consideri il controllo integrità di esempio seguente, che accetta arg1 e arg2 come parametri del costruttore:

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);
    

    La firma precedente indica che il controllo integrità richiede dati personalizzati per elaborare la logica del probe del controllo integrità. I dati vengono forniti al delegato usato per creare l'istanza del controllo di integrità quando il controllo di integrità viene registrato con un metodo di estensione. Nell'esempio seguente il chiamante specifica:

    • arg1: punto dati integer per il controllo integrità.
    • arg2: argomento stringa per il controllo integrità.
    • name: nome facoltativo del controllo integrità. Se null, viene usato un valore predefinito.
    • failureStatus: oggetto facoltativo HealthStatusche viene segnalato per uno stato di errore. Se null, viene usato HealthStatus.Unhealthy.
    • tags: raccolta facoltativa IEnumerable<string> di tag.
    public static class SampleHealthCheckBuilderExtensions
    {
        private const string DefaultName = "Sample";
    
        public static IHealthChecksBuilder AddSampleHealthCheck(
            this IHealthChecksBuilder healthChecksBuilder,
            int arg1,
            string arg2,
            string? name = null,
            HealthStatus? failureStatus = null,
            IEnumerable<string>? tags = default)
        {
            return healthChecksBuilder.Add(
                new HealthCheckRegistration(
                    name ?? DefaultName,
                    _ => new SampleHealthCheckWithArgs(arg1, arg2),
                    failureStatus,
                    tags));
        }
    }
    

Server di pubblicazione dei controlli di integrità

Quando IHealthCheckPublisher viene aggiunto al contenitore del servizio, il sistema di controllo dell'integrità esegue periodicamente i controlli di integrità e chiama PublishAsync con il risultato. Questo processo è utile in uno scenario di sistema di monitoraggio dell'integrità basato su push che prevede che ogni processo chiami periodicamente il sistema di monitoraggio per determinare l'integrità.

HealthCheckPublisherOptions consente di impostare:

  • Delay: ritardo iniziale applicato dopo l'avvio dell'app prima dell'esecuzione delle IHealthCheckPublisher istanze. Il ritardo viene applicato una sola volta all'avvio e non si applica alle iterazioni successive. Il valore predefinito è cinque secondi.
  • Period: periodo di IHealthCheckPublisher esecuzione. Il valore predefinito è 30 secondi.
  • Predicate: se Predicate è null (impostazione predefinita), il servizio di pubblicazione controllo integrità esegue tutti i controlli di integrità registrati. Per eseguire un subset dei controlli di integrità, specificare una funzione che filtra il set di controlli. Il predicato viene valutato per ogni periodo.
  • Timeout: timeout per l'esecuzione dei controlli di integrità per tutte le IHealthCheckPublisher istanze. Usare InfiniteTimeSpan per l'esecuzione senza un timeout. Il valore predefinito è 30 secondi.

Nell'esempio seguente viene illustrato il layout di un editore di integrità:

public class SampleHealthCheckPublisher : IHealthCheckPublisher
{
    public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            // ...
        }
        else
        {
            // ...
        }

        return Task.CompletedTask;
    }
}

La HealthCheckPublisherOptions classe fornisce proprietà per la configurazione del comportamento dell'autore del controllo integrità.

Nell'esempio seguente viene registrato un server di pubblicazione del controllo integrità come singleton e viene configurato HealthCheckPublisherOptions:

builder.Services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = healthCheck => healthCheck.Tags.Contains("sample");
});

builder.Services.AddSingleton<IHealthCheckPublisher, SampleHealthCheckPublisher>();

Nota

AspNetCore.Diagnostics.HealthChecks include editori per diversi sistemi, tra cui Application Insights.

AspNetCore.Diagnostics.HealthChecks non è gestito o supportato da Microsoft.

Inserimento delle dipendenze e controlli di integrità

È possibile usare l'inserimento delle dipendenze per utilizzare un'istanza di un oggetto specifico Type all'interno di una classe Controllo integrità. L'inserimento delle dipendenze può essere utile per inserire opzioni o una configurazione globale in un controllo integrità. L'uso dell'inserimento delle dipendenze non è uno scenario comune per configurare i controlli di integrità. In genere, ogni controllo integrità è piuttosto specifico del test effettivo ed è configurato usando IHealthChecksBuilder i metodi di estensione.

L'esempio seguente mostra un esempio di controllo integrità che recupera un oggetto di configurazione tramite l'inserimento delle dipendenze:

public class SampleHealthCheckWithDI : IHealthCheck
{
    private readonly SampleHealthCheckWithDiConfig _config;

    public SampleHealthCheckWithDI(SampleHealthCheckWithDiConfig config)
        => _config = config;

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // use _config ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

E SampleHealthCheckWithDiConfig il controllo integrità deve essere aggiunto al contenitore del servizio :

builder.Services.AddSingleton<SampleHealthCheckWithDiConfig>(new SampleHealthCheckWithDiConfig
{
    BaseUriToCheck = new Uri("https://sample.contoso.com/api/")
});
builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheckWithDI>(
        "With Dependency Injection",
        tags: new[] { "inject" });

UseHealthChecks e MapHealthChecks

Esistono due modi per rendere i controlli di integrità accessibili ai chiamanti:

  • UseHealthChecks registra il middleware per la gestione delle richieste di controlli di integrità nella pipeline middleware.
  • MapHealthChecks registra un endpoint dei controlli di integrità. L'endpoint viene confrontato ed eseguito insieme ad altri endpoint nell'app.

Il vantaggio dell'uso MapHealthChecks di oltre UseHealthChecks è la possibilità di usare il middleware con riconoscimento degli endpoint, ad esempio l'autorizzazione, e di avere un maggiore controllo granulare sui criteri di corrispondenza. Il vantaggio principale dell'uso UseHealthChecks di over MapHealthChecks è controllare esattamente dove vengono eseguiti i controlli di integrità nella pipeline middleware.

UseHealthChecks:

  • Termina la pipeline quando una richiesta corrisponde all'endpoint del controllo integrità. Il corto circuito è spesso auspicabile perché evita operazioni non necessarie, ad esempio la registrazione e altri middleware.
  • Viene usato principalmente per configurare il middleware di controllo integrità nella pipeline.
  • Può corrispondere a qualsiasi percorso di una porta con un null oggetto o vuoto PathString. Consente di eseguire un controllo di integrità su qualsiasi richiesta effettuata sulla porta specificata.
  • Codice sorgente

MapHealthChecks Permette:

  • Mapping di route o endpoint specifici per i controlli di integrità.
  • Personalizzazione dell'URL o del percorso in cui l'endpoint del controllo integrità è accessibile.
  • Mapping di più endpoint di controllo integrità con route o configurazioni diverse. Supporto di più endpoint:
    • Abilita endpoint separati per diversi tipi di controlli di integrità o componenti.
    • Viene usato per distinguere i diversi aspetti dell'integrità dell'app o applicare configurazioni specifiche ai subset di controlli di integrità.
  • Codice sorgente

Risorse aggiuntive

Nota

Questo articolo è stato in parte creato con l'aiuto dell'intelligenza artificiale. Prima della pubblicazione, un autore ha rivisto e revisionato il contenuto secondo necessità. Vedi Principi per l'utilizzo dei contenuti generati dall'intelligenza artificiale in Microsoft Learn.