Integritätsprüfungen in ASP.NET Core

Von Glenn Condron und Jürgen Gutsch

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der ASP.NET Core 8.0-Version dieses Artikels.

ASP.NET Core bietet Middleware für Integritätsprüfungen und Bibliotheken für die Berichterstellung für Komponenten der App-Infrastruktur.

Integritätsprüfungen werden von einer App als HTTP-Endpunkte verfügbar gemacht. Endpunkte für die Integritätsprüfung können für verschiedene Echtzeitüberwachungsszenarien konfiguriert werden:

  • Integritätstests können von Containerorchestratoren und Lastenausgleichsmodulen verwendet werden, um den Status einer App zu überprüfen. Ein Containerorchestrator kann z.B. auf eine fehlerhafte Integritätsprüfung reagieren, indem die Ausführung einer Bereitstellung angehalten oder ein Container neu gestartet wird. Ein Lastenausgleichsmodul kann auf eine fehlerhafte App reagieren, indem Datenverkehr von der fehlerhaften zu einer fehlerfreien Instanz umgeleitet wird.
  • Die Nutzung von Arbeitsspeicher, Datenträgern und anderen physischen Serverressourcen kann auf einen fehlerfreien Status überwacht werden.
  • Integritätsprüfungen können die Abhängigkeiten einer App testen, wie z.B. Datenbanken und externe Dienstendpunkte, um Verfügbarkeit und normale Funktionsweise zu bestätigen.

Integritätsprüfungen werden in der Regel mit einem externen Überwachungsdienst oder Containerorchestrator verwendet, um den Status einer App zu überprüfen. Bevor Sie Integritätsprüfungen zu einer App hinzufügen, entscheiden Sie, welches Überwachungssystem verwendet werden soll. Das Überwachungssystem bestimmt, welche Arten von Integritätsprüfungen erstellt und wie die jeweiligen Endpunkte konfiguriert werden müssen.

Grundlegender Integritätstest

In vielen Apps genügt zur Ermittlung des App-Status eine grundlegende Integritätstestkonfiguration, die die Verfügbarkeit der App für die Verarbeitung von Anforderungen (Lebendigkeit) meldet.

Die grundlegende Konfiguration registriert Integritätsprüfungsdienste und ruft die Middleware für Integritätsprüfungen auf, damit diese an einem URL-Endpunkt mit dem Integritätsstatus antwortet. Standardmäßig werden keine spezifischen Integritätsprüfungen registriert, um eine bestimmte Abhängigkeit oder ein bestimmtes Subsystem zu testen. Die App wird als fehlerfrei angesehen, wenn sie an der URL des Integritätsendpunkts antworten kann. Der Standardantwortwriter schreibt HealthStatus als Klartextantwort an den Client. HealthStatus ist HealthStatus.Healthy, HealthStatus.Degraded oder HealthStatus.Unhealthy.

Registrieren Sie Integritätsprüfungsdienste mit AddHealthChecks in Program.cs. Erstellen Sie einen Integritätsprüfungsendpunkt durch Aufrufen von MapHealthChecks.

Im folgenden Beispiel wird ein Integritätsprüfungsendpunkt unter /healthz erstellt:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

Docker bietet eine integrierte HEALTHCHECK-Direktive, mit der Sie den Status einer App überprüfen können, die die grundlegende Konfiguration für Integritätsprüfungen verwendet:

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

Das vorherige Beispiel verwendet curl, um eine HTTP-Anforderung an den Integritätsprüfungsendpunkt bei /healthz auszugeben. curl ist nicht in den .NET Linux-Containerimages enthalten, kann aber hinzugefügt werden, indem das erforderliche Paket in der Dockerfile installiert wird. Container, die auf Alpine Linux basierende Images verwenden, können das enthaltene wget anstelle von curl verwenden.

Erstellen von Integritätsprüfungen

Integritätsprüfungen werden durch Implementieren der IHealthCheck-Schnittstelle erstellt. Die CheckHealthAsync-Methode gibt ein HealthCheckResult zurück, das die Integrität als Healthy, Degraded oder Unhealthy angibt. Das Ergebnis wird als Klartextantwort mit einem konfigurierbaren Statuscode geschrieben. Die Konfiguration wird im Abschnitt Integritätsprüfungsoptionen beschrieben. HealthCheckResult kann auch optionale Schlüssel-Wert-Paare zurückgeben.

Das folgende Beispiel veranschaulicht das Layout einer Integritätsprüfung:

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."));
    }
}

Die Integritätsprüfungslogik wird in der CheckHealthAsync-Methode platziert. Im vorherigen Beispiel wird die Dummyvariable isHealthy auf true festgelegt. Wenn der Wert von isHealthy auf false festgelegt ist, wird der HealthCheckRegistration.FailureStatus-Status zurückgegeben.

Wenn CheckHealthAsync während der Überprüfung eine Ausnahme auslöst, wird ein neues Element HealthReportEntry zurückgegeben, dessen HealthReportEntry.Status auf FailureStatus festgelegt ist. Dieser Status ist definiert durch AddCheck (weitere Informationen finden Sie im Abschnitt Registrieren von Diensten zur Integritätsprüfung) und enthält die innere Ausnahme, die den Prüfungsfehler verursacht hat. Description ist auf die Meldung der Ausnahme festgelegt.

Registrieren von Integritätsprüfungsdiensten

Rufen Sie AddCheck in Program.cs auf, um einen Integritätsprüfungsdienst zu registrieren:

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

Die in der folgenden Abbildung gezeigte AddCheck-Überladung legt den Fehlerstatus (HealthStatus) fest, der angegeben werden soll, wenn die Integritätsprüfung einen Fehler meldet. Wenn der Fehlerstatus auf null (Standardwert) festgelegt ist, wird HealthStatus.Unhealthy gemeldet. Diese Überladung ist ein nützliches Szenario für Bibliotheksersteller: Bei einem Integritätsprüfungsfehler wird der durch die Bibliothek angegebene Fehlerstatus von der App erzwungen, wenn die Implementierung der Integritätsprüfung die Einstellung berücksichtigt.

Tags können zum Filtern von Integritätsprüfungen verwendet werden. Tags werden im Abschnitt Filtern von Integritätsprüfungen beschrieben.

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

AddCheck kann auch eine Lambdafunktion ausführen. Im folgenden Beispiel gibt die Integritätsprüfung immer ein fehlerfreies Ergebnis zurück:

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

Rufen Sie AddTypeActivatedCheck auf, um Argumente an die Implementierung einer Integritätsprüfung zu übergeben. Im folgenden Beispiel akzeptiert eine typaktivierte Integritätsprüfung in ihrem Konstruktor eine ganze Zahl und eine Zeichenfolge:

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."));
    }
}

Um die vorherige Integritätsprüfung zu registrieren, rufen Sie AddTypeActivatedCheck mit der ganzen Zahl und der Zeichenfolge auf, die als Argumente übergeben werden:

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

Verwenden von Integritätsprüfungsrouting

Rufen Sie in Program.cs auf der Endpunkterstellung mit der Endpunkt-URL oder dem relativen Pfad MapHealthChecks auf:

app.MapHealthChecks("/healthz");

Anfordern des Hosts

Rufen Sie RequireHost auf, um einen oder mehrere zugelassene Hosts für den Integritätsprüfungs-Endpunkt anzugeben. Hosts sollten Unicode anstelle von Punycode verwenden und können einen Port enthalten. Wenn keine Sammlung bereitgestellt wird, wird jeder Host akzeptiert:

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

Um den Integritätsprüfungsendpunkt so einzuschränken, dass er nur an einem bestimmten Port antwortet, geben Sie beim Aufruf von RequireHost einen Port an. Dieser Ansatz wird normalerweise in einer Containerumgebung verfolgt, um einen Port für Überwachungsdienste verfügbar zu machen:

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

Warnung

Die APIs, die auf dem Hostheader basieren, z. B. HttpRequest.Host und RequireHost, sind potenziellem Spoofing durch Clients ausgesetzt.

Verwenden Sie einen der folgenden Ansätze, um Host- und Portspoofing zu verhindern:

Um zu verhindern, dass nicht autorisierte Clients den Port spoofen, rufen Sie RequireAuthorization auf:

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

Weitere Informationen finden Sie unter Hostabgleich in Routen mit RequireHost.

Anfordern der Autorisierung

Rufen Sie RequireAuthorization auf, um die Autorisierungsmiddleware auf dem Integritätsprüfungs-Anforderungsendpunkt auszuführen. Eine RequireAuthorization-Überladung akzeptiert eine oder mehrere Autorisierungsrichtlinien. Wenn keine Richtlinie bereitgestellt wird, wird die standardmäßige Autorisierungsrichtlinie verwendet:

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

Aktivieren ursprungsübergreifender Anforderungen (CORS)

Obwohl das manuelle Ausführen von Integritätsprüfungen über einen Browser kein gängiges Szenario ist, kann CORS-Middleware durch Aufrufen von RequireCors für Integritätsprüfungsendpunkte aktiviert werden. Eine RequireCors-Überladung akzeptiert einen CORS-Richtliniengenerator-Delegaten (CorsPolicyBuilder) oder einen Richtliniennamen. Weitere Informationen finden Sie unter Aktivieren ursprungsübergreifender Anforderungen (Cross-Origin Requests, CORS) in ASP.NET Core.

Optionen für die Integritätsprüfung

HealthCheckOptions ermöglichen die Anpassung des Verhaltens von Integritätsprüfungen:

Filtern von Integritätsprüfungen

Standardmäßig führt die Middleware für Integritätsprüfungen alle registrierten Integritätsprüfungen aus. Um eine Teilmenge von Integritätsprüfungen auszuführen, stellen Sie eine Funktion bereit, die einen booleschen Wert an die Option Predicate zurückgibt.

Im folgenden Beispiel werden die Integritätsprüfungen so gefiltert, dass nur die mit sample gekennzeichneten ausgeführt werden:

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

Anpassen des HTTP-Statuscodes

Verwenden Sie ResultStatusCodes, um die Zuordnung des Integritätsstatus zu HTTP-Statuscodes anzupassen. Die folgenden StatusCodes-Zuweisungen stellen die von der Middleware verwendeten Standardwerte dar. Ändern Sie die Statuscodewerte so, dass sie Ihren Anforderungen entsprechen:

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

Unterdrücken von Cacheheadern

AllowCachingResponses steuert, ob die Middleware für Integritätsprüfungen einer Testantwort HTTP-Header hinzufügt, um das Zwischenspeichern von Antworten zu verhindern. Wenn der Wert false (Standard) lautet, legt die Middleware die Header Cache-Control, Expires und Pragma fest oder überschreibt sie, um eine Zwischenspeicherung der Antworten zu verhindern. Wenn der Wert true lautet, ändert die Middleware die Cacheheader der Antwort nicht:

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

Anpassen der Ausgabe

Um die Ausgabe eines Integritätsprüfungsberichts anzupassen, legen Sie die Eigenschaft HealthCheckOptions.ResponseWriter für einen Delegaten fest, der die Antwort schreibt:

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

Der Standarddelegat schreibt eine minimale Klartextantwort mit dem Zeichenfolgenwert HealthReport.Status. Der folgende benutzerdefinierte Delegat gibt eine benutzerdefinierte JSON-Antwort mithilfe von System.Text.Json aus:

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()));
}

Die Integritätsprüfungs-API bietet keine integrierte Unterstützung für komplexe JSON-Rückgabeformate, da das Format für Ihre Überwachungssystemauswahl spezifisch ist. Passen Sie die Antwort in den vorangehenden Beispielen nach Bedarf an. Weitere Informationen zur JSON-Serialisierung mit System.Text.Json finden Sie unter Serialisieren und Deserialisieren von JSON in .NET.

Datenbanktest

Eine Integritätsprüfung kann eine Datenbankabfrage angeben, die als boolescher Test ausgeführt wird, um zu ermitteln, ob die Datenbank normal reagiert.

AspNetCore.Diagnostics.HealthChecks, eine Integritätsprüfungsbibliothek für ASP.NET Core-Apps, enthält eine Integritätsprüfung, die für eine SQL Server-Datenbank ausgeführt wird. AspNetCore.Diagnostics.HealthChecks führt eine SELECT 1-Abfrage in der Datenbank aus, um zu bestätigen, dass die Verbindung mit der Datenbank fehlerfrei ist.

Warnung

Wenn Sie die Datenbankverbindung mithilfe einer Abfrage überprüfen, wählen Sie eine Abfrage aus, die eine schnelle Antwort zurückgibt. Bei einer Abfrage besteht immer das Risiko, dass die Datenbank überladen und ihre Leistung beeinträchtigt wird. In den meisten Fällen ist es nicht notwendig, eine Testabfrage auszuführen. Es genügt zumeist, einfach erfolgreich eine Verbindung mit der Datenbank herzustellen. Wenn Sie eine Abfrage ausführen müssen, wählen Sie eine einfache SELECT-Abfrage aus, wie z.B. SELECT 1.

Um diese SQL Server-Integritätsprüfung zu verwenden, fügen Sie einen Paketverweis auf das NuGet-Paket AspNetCore.HealthChecks.SqlServer ein. Im folgenden Beispiel wird die SQL Server-Integritätsüberprüfung registriert:

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);

Hinweis

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Entity Framework Core-DbContext-Test

Die DbContext-Überprüfung bestätigt, dass die App mit der Datenbank kommunizieren kann, die für einen EF Core-DbContext konfiguriert wurde. Die DbContext Überprüfung wird in Apps unterstützt, für die gilt:

AddDbContextCheck registriert eine Integritätsprüfung für einen DbContext. DbContext wird der Methode als TContext bereitgestellt. Eine Überladung ist verfügbar, um den Fehlerstatus, Tags sowie eine benutzerdefinierte Testabfrage zu konfigurieren.

Standardmäßig:

  • Der DbContextHealthCheck ruft die CanConnectAsync-Methode von EF Core auf. Sie können festlegen, welcher Vorgang ausgeführt wird, wenn die Integrität mit AddDbContextCheck-Methodenüberladungen überprüft wird.
  • Der Name der Integritätsprüfung ist der Name des TContext-Typs.

Im folgenden Beispiel werden ein DbContext und ein zugeordneter DbContextHealthCheck registriert:

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

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

Separate Tests für Bereitschaft und Lebendigkeit

In einigen Hostingszenarien wird ein Integritätsprüfungspaar verwendet, mit dem zwischen zwei App-Status unterschieden wird:

  • Bereitschaft gibt an, ob die App ordnungsgemäß ausgeführt wird, aber nicht für den Empfang von Anforderungen bereit ist.
  • Livetest gibt an, ob eine App abgestürzt ist und neu gestartet werden muss.

Betrachten Sie das folgende Beispiel: Eine App muss eine große Konfigurationsdatei herunterladen, bevor sie für die Verarbeitung von Anforderungen bereit ist. Wir möchten nicht, dass die App neu gestartet wird, wenn der erste Download fehlschlägt, da die App mehrmals versuchen kann, die Datei herunterzuladen. Wir verwenden einen Livetest, um den Livezustand des Prozesses zu beschreiben. Weitere Überprüfungen erfolgen nicht. Außerdem soll verhindert werden, dass Anforderungen an die App gesendet werden, bevor die Konfigurationsdatei erfolgreich heruntergeladen wurde. Wir verwenden einen Bereitschaftstest, um den Status "nicht bereit" anzugeben, bis der Download erfolgreich durchgeführt wurde und die App für den Empfang von Anforderungen bereit ist.

Die folgende Hintergrundaufgabe simuliert einen Startprozess, der ungefähr 15 Sekunden dauert. Nach Abschluss des Vorgangs legt die Aufgabe die StartupHealthCheck.StartupCompleted-Eigenschaft auf TRUE fest:

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;
    }
}

StartupHealthCheck meldet die Beendigung der lang ausgeführten Startaufgabe und macht die Eigenschaft StartupCompleted verfügbar, die vom Hintergrunddienst festgelegt wird:

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."));
    }
}

Die Integritätsprüfung wird mit AddCheck zusammen mit dem gehosteten Dienst in Program.cs registriert. Da der gehostete Dienst die Eigenschaft in der Integritätsprüfung festlegen muss, wird die Integritätsprüfung ebenfalls im Dienstcontainer als Singleton registriert:

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

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

Um zwei verschiedene Integritätsprüfungsendpunkte zu erstellen, rufen Sie MapHealthChecks zweimal auf:

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

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

Im vorherigen Beispiel werden die folgenden Integritätsprüfungsendpunkte erstellt:

  • /healthz/ready für die Bereitschaftsprüfung. Die Bereitschaftsprüfung filtert Integritätsprüfungen heraus, die mit ready gekennzeichnet sind.
  • /healthz/live für die Lebendigkeitsprüfung. Die Liveüberprüfung filtert alle Integritätsprüfungen heraus, indem false im Delegaten HealthCheckOptions.Predicate zurückgegeben wird. Weitere Informationen zum Filtern von Integritätsprüfungen finden Sie unter Filtern von Integritätsprüfungen in diesem Artikel.

Bevor die Startaufgabe abgeschlossen ist, meldet der Endpunkt /healthz/ready den Status Unhealthy. Bevor die Startaufgabe abgeschlossen ist, meldet dieser Endpunkt den Status Healthy. Der Endpunkt /healthz/live schließt alle Überprüfungen aus und meldet für alle Aufrufe den Status Healthy.

Kubernetes-Beispiel

Die Verwendung von Bereitschafts- und Lebendigkeitstests ist in Umgebungen wie Kubernetes sehr nützlich. In Kubernetes muss eine App möglicherweise zeitaufwendige Startaufgaben ausführen, bevor sie Anforderungen wie z. B. das Testen der Verfügbarkeit der zugrunde liegenden Datenbank erfüllt. Durch Verwendung separater Überprüfungen kann der Orchestrator unterscheiden, ob eine App funktioniert, aber noch nicht bereit ist, oder ob die App nicht gestartet wurde. Weitere Informationen zu Bereitschafts- und Lebendigkeitstests in Kubernetes finden Sie in der Kubernetes-Dokumentation unter Configure Liveness and Readiness Probes (Konfigurieren von Lebendigkeits- und Bereitschaftstests).

Das folgende Beispiel veranschaulicht die Konfiguration eines Bereitschaftstests in 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

Verteilen einer Integritätsprüfungsbibliothek

So verteilen Sie eine Integritätsprüfung als Bibliothek:

  1. Schreiben Sie eine Integritätsprüfung, die die IHealthCheck-Schnittstelle als eigenständige Klasse implementiert. Die Klasse kann Abhängigkeitsinjektion (Dependency Injection, DI), Typaktivierung und benannte Optionen verwenden, um auf Konfigurationsdaten zuzugreifen.

  2. Schreiben Sie eine Erweiterungsmethode mit Parametern, die von der nutzenden App in ihrer Program.cs-Methode aufgerufen werden. Betrachten Sie das folgende Beispiel einer Integritätsprüfung, die arg1 und arg2 als Konstruktorparameter akzeptiert:

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

    Die vorherige Signatur gibt an, dass die Integritätsprüfung benutzerdefinierte Daten benötigt, um die Prüflogik der Integritätsprüfung zu verarbeiten. Die Daten werden für den Delegaten bereitgestellt, der zum Erstellen der Integritätsprüfungsinstanz verwendet wird, wenn die Integritätsprüfung bei einer Erweiterungsmethode registriert wird. Im folgenden Beispiel gibt der Aufrufer Folgendes an:

    • arg1: ein integer-Datenpunkt für die Integritätsprüfung.
    • arg2: ein Zeichenfolgenargument für die Integritätsprüfung.
    • name: ein optionaler Name der Integritätsprüfung. Falls null, wird ein Standardwert verwendet.
    • failureStatus: ein optionales Element HealthStatus, das bei einem Fehlerstatus gemeldet wird. Wenn der Wert null ist, wird HealthStatus.Unhealthy verwendet.
    • tags: eine optionale IEnumerable<string>-Sammlung von Tags.
    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));
        }
    }
    

Herausgeber der Integritätsprüfung

Wenn dem Dienstcontainer ein IHealthCheckPublisher hinzugefügt wird, führt das Integritätsprüfungssystem Ihre Integritätsprüfungen regelmäßig aus und ruft PublishAsync mit dem Ergebnis auf. Dieser Prozess ist nützlich in einem Szenario mit pushbasiertem Integritätsüberwachungssystem, in dem jeder Prozess das Überwachungssystem regelmäßig aufrufen muss, um Integrität zu bestimmen.

HealthCheckPublisherOptions ermöglichen Ihnen, Folgendes festzulegen:

  • Delay: Hierbei handelt es sich um die angewendete anfängliche Verzögerung zwischen dem Start der App und der Ausführung von IHealthCheckPublisher-Instanzen. Die Verzögerung wird einmal beim Start angewendet und gilt nicht für spätere Iterationen. Der Standardwert beträgt fünf Sekunden.
  • Period: Hierbei handelt es sich um die Dauer der Ausführung von IHealthCheckPublisher. Der Standardwert ist 30 Sekunden.
  • Predicate: Wenn der Wert für Predicatenull ist (Standard), führt der Veröffentlichungsdienst für die Integritätsprüfung alle registrierten Integritätsprüfungen durch. Um eine Teilmenge von Integritätsprüfungen auszuführen, stellen Sie eine Funktion bereit, die die Menge der Prüfungen filtert. Das Prädikat wird in jedem Zeitraum ausgewertet.
  • Timeout: Hierbei handelt es sich um das Zeitlimit für die Ausführung der Integritätsprüfungen für alle IHealthCheckPublisher-Instanzen. Verwenden Sie InfiniteTimeSpan zur Ausführung ohne Timeout. Der Standardwert ist 30 Sekunden.

Das folgende Beispiel veranschaulicht das Layout eines Integritätsprüfungsherausgebers:

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

        return Task.CompletedTask;
    }
}

Die HealthCheckPublisherOptions-Klasse stellt Eigenschaften zum Konfigurieren des Verhaltens des Integritätsprüfungsherausgebers bereit.

Im folgenden Beispiel wird ein Integritätsprüfungsherausgeber als Singleton registriert und HealthCheckPublisherOptions konfiguriert:

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:

  • Enthält Herausgeber für verschiedene Systeme, einschließlich Application Insights.
  • Wird von Microsoft nicht verwaltet oder unterstützt.

Individuelle Integritätsprüfungen

Delayund Period können jeweils einzeln für HealthCheckRegistration festgelegt werden. Dies ist nützlich, wenn Sie einige Integritätsprüfungen in einem anderen Rhythmus als dem in HealthCheckPublisherOptions festgelegten Zeitraum durchführen möchten.

Mit dem folgenden Code wird Delay und Period für SampleHealthCheck1 festgelegt:

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();

Abhängigkeitsinjektion und Integritätsprüfungen

Es ist möglich, eine Instanz eines bestimmten Type innerhalb einer Integritätsprüfungsklasse über eine Abhängigkeitsinjektion zu verwenden. Die Abhängigkeitsinjektion kann hilfreich sein, um Optionen oder eine globale Konfiguration in eine Integritätsprüfung einzufügen. Die Verwendung der Abhängigkeitsinjektion ist kein gängiges Szenario zum Konfigurieren von Integritätsprüfungen. In der Regel ist jede Integritätsprüfung spezifisch für den tatsächlichen Test und wird mithilfe von IHealthChecksBuilder-Erweiterungsmethoden konfiguriert.

Das folgende Beispiel zeigt ein Beispiel für eine Integritätsprüfung, die ein Konfigurationsobjekt über eine Abhängigkeitsinjektion abruft:

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."));
    }
}

SampleHealthCheckWithDiConfig und die Integritätsprüfung müssen dem Dienstcontainer hinzugefügt werden:

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 im Vergleich zu MapHealthChecks

Es gibt zwei Möglichkeiten, Integritätsprüfungen für Aufrufer zugänglich zu machen:

  • UseHealthChecks registriert Middleware für die Verarbeitung von Integritätsprüfungsanforderungen in der Middlewarepipeline.
  • MapHealthChecks registriert einen Integritätsprüfungsendpunkt. Der Endpunkt wird zusammen mit anderen Endpunkten in der App abgeglichen und ausgeführt.

Der Vorteil der Verwendung von MapHealthChecks gegenüber UseHealthChecks ist die Möglichkeit, endpunktfähige Middleware wie Autorisierung zu verwenden und eine präzisere Kontrolle über die Abgleichsrichtlinie zu haben. Der Hauptvorteil der Verwendung von UseHealthChecks gegenüber MapHealthChecks besteht darin, genau zu steuern, wo Integritätsprüfungen in der Middlewarepipeline ausgeführt werden.

UseHealthChecks:

  • Beendet die Pipeline, wenn eine Anforderung mit dem Integritätsprüfungsendpunkt übereinstimmt. Kurzschlüsse sind häufig wünschenswert, da dadurch unnötige Arbeit vermieden wird, z. B. Protokollierung und andere Middleware.
  • Wird in erster Linie zum Konfigurieren der Integritätsprüfungsmiddleware in der Pipeline verwendet.
  • Kann einen beliebigen Pfad an einem Port mit einem null-Wert oder einem leeren PathString-Wert abgleichen. Ermöglicht das Durchführen einer Integritätsprüfung für jede Anforderung, die an den angegebenen Port gestellt wird.
  • Quellcode

MapHealthChecks ermöglicht:

  • Beendet die Pipeline, wenn eine Anforderung mit dem Integritätsprüfungsendpunkt übereinstimmt, indem ShortCircuit aufgerufen wird. Beispiel: app.MapHealthChecks("/healthz").ShortCircuit();. Weitere Informationen finden Sie unter Kurzschluss der Middleware nach dem Routing.
  • Zuordnen bestimmter Routen oder Endpunkte für Integritätsprüfungen.
  • Anpassen der URL oder des Pfads, unter der bzw. dem auf den Integritätsprüfungsendpunkt zugegriffen werden kann.
  • Zuordnen mehrerer Integritätsprüfungsendpunkte mit unterschiedlichen Routen oder Konfigurationen. Unterstützung mehrerer Endpunkte:
    • Aktiviert separate Endpunkte für verschiedene Arten von Integritätsprüfungen oder -komponenten.
    • Wird verwendet, um zwischen verschiedenen Aspekten der App-Integrität zu unterscheiden oder bestimmte Konfigurationen auf Teilmengen von Integritätsprüfungen anzuwenden.
  • Quellcode

Zusätzliche Ressourcen

Hinweis

Dieser Artikel wurde teilweise mit Hilfe künstlicher Intelligenz erstellt. Vor der Veröffentlichung hat ein Autor den Inhalt geprüft und nach Bedarf überarbeitet. Weitere Informationen finden Sie unter Unsere Prinzipien für die Verwendung von KI-generierten Inhalten in Microsoft Learn.

ASP.NET Core bietet Middleware für Integritätsprüfungen und Bibliotheken für die Berichterstellung für Komponenten der App-Infrastruktur.

Integritätsprüfungen werden von einer App als HTTP-Endpunkte verfügbar gemacht. Endpunkte für die Integritätsprüfung können für verschiedene Echtzeitüberwachungsszenarien konfiguriert werden:

  • Integritätstests können von Containerorchestratoren und Lastenausgleichsmodulen verwendet werden, um den Status einer App zu überprüfen. Ein Containerorchestrator kann z.B. auf eine fehlerhafte Integritätsprüfung reagieren, indem die Ausführung einer Bereitstellung angehalten oder ein Container neu gestartet wird. Ein Lastenausgleichsmodul kann auf eine fehlerhafte App reagieren, indem Datenverkehr von der fehlerhaften zu einer fehlerfreien Instanz umgeleitet wird.
  • Die Nutzung von Arbeitsspeicher, Datenträgern und anderen physischen Serverressourcen kann auf einen fehlerfreien Status überwacht werden.
  • Integritätsprüfungen können die Abhängigkeiten einer App testen, wie z.B. Datenbanken und externe Dienstendpunkte, um Verfügbarkeit und normale Funktionsweise zu bestätigen.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Die Beispiel-App enthält Beispiele der in diesem Artikel beschriebenen Szenarien. Um die Beispiel-App für ein bestimmtes Szenario auszuführen, verwenden Sie den Befehl dotnet run aus dem Ordner des Projekts in einer Befehlsshell. Informationen zur Verwendung der Beispiel-App finden Sie in der zugehörigen Datei README.md und den Szenariobeschreibungen in diesem Artikel.

Voraussetzungen

Integritätsprüfungen werden in der Regel mit einem externen Überwachungsdienst oder Containerorchestrator verwendet, um den Status einer App zu überprüfen. Bevor Sie Integritätsprüfungen zu einer App hinzufügen, entscheiden Sie, welches Überwachungssystem verwendet werden soll. Das Überwachungssystem bestimmt, welche Arten von Integritätsprüfungen erstellt und wie die jeweiligen Endpunkte konfiguriert werden müssen.

Für ASP.NET Core-Apps wird implizit auf das Paket Microsoft.AspNetCore.Diagnostics.HealthChecks verwiesen. Fügen Sie einen Verweis auf das Paket Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore hinzu, um Integritätsprüfungen mit Entity Framework Core durchzuführen.

Die Beispiel-App stellt Startcode bereit, um die Integritätsprüfungen für verschiedene Szenarien zu veranschaulichen. Das Szenario Datenbanktest überprüft die Integrität einer Datenbankverbindung mithilfe von AspNetCore.Diagnostics.HealthChecks. Im Szenario DbContext-Test wird eine Datenbank mithilfe eines EF Core-DbContext überprüft. Für ein Erkunden der Datenbankszenarios gilt für die Beispiel-App:

Hinweis

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Ein anderes Szenario für Integritätsprüfungen zeigt, wie Sie Integritätsprüfungen auf einen Verwaltungsport filtern können. Für die Beispiel-App müssen Sie eine Properties/launchSettings.json-Datei erstellen, die die Verwaltungs-URL und den Verwaltungsport enthält. Weitere Informationen finden Sie im Abschnitt Filtern nach Port.

Grundlegender Integritätstest

In vielen Apps genügt zur Ermittlung des App-Status eine grundlegende Integritätstestkonfiguration, die die Verfügbarkeit der App für die Verarbeitung von Anforderungen (Lebendigkeit) meldet.

Die grundlegende Konfiguration registriert Integritätsprüfungsdienste und ruft die Middleware für Integritätsprüfungen auf, damit diese an einem URL-Endpunkt mit dem Integritätsstatus antwortet. Standardmäßig werden keine spezifischen Integritätsprüfungen registriert, um eine bestimmte Abhängigkeit oder ein bestimmtes Subsystem zu testen. Die App wird als fehlerfrei angesehen, wenn sie an der URL des Integritätsendpunkts antworten kann. Der standardmäßig verwendete Antwortwriter schreibt den Status (HealthStatus) als Nur-Text-Antwort zurück an den Client und gibt dabei den Status HealthStatus.Healthy, HealthStatus.Degraded oder HealthStatus.Unhealthy an.

Registrieren Sie Integritätsprüfungsdienste mit AddHealthChecks in Startup.ConfigureServices. Erstellen Sie einen Integritätsprüfungs-Endpunkt durch Aufrufen von MapHealthChecks in Startup.Configure.

In der Beispiel-App wird der Integritätsprüfungs-Endpunkt in /health (BasicStartup.cs) erstellt:

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

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

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

Um das Szenario für die grundlegende Konfiguration mithilfe der Beispiel-App auszuführen, verwenden Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell:

dotnet run --scenario basic

Docker-Beispiel

Docker bietet eine integrierte HEALTHCHECK-Direktive, mit der Sie den Status einer App überprüfen können, die die grundlegende Konfiguration für Integritätsprüfungen verwendet:

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

Erstellen von Integritätsprüfungen

Integritätsprüfungen werden durch Implementieren der IHealthCheck-Schnittstelle erstellt. Die CheckHealthAsync-Methode gibt ein HealthCheckResult zurück, das die Integrität als Healthy, Degraded oder Unhealthy angibt. Das Ergebnis wird als Klartextantwort mit einem konfigurierbaren Statuscode geschrieben (diese Konfiguration wird im Abschnitt Optionen für die Integritätsprüfung beschrieben). HealthCheckResult kann auch optionale Schlüssel-Wert-Paare zurückgeben.

Die folgende ExampleHealthCheck-Klasse veranschaulicht das Layout einer Integritätsprüfung. Die Integritätsprüfungslogik wird in der CheckHealthAsync-Methode platziert. Im folgenden Beispiel wird eine Dummyvariable healthCheckResultHealthy auf true festgelegt. Wenn der Wert von healthCheckResultHealthy auf false festgelegt ist, wird der HealthCheckRegistration.FailureStatus-Status zurückgegeben.

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."));
    }
}

Wenn CheckHealthAsync während der Überprüfung eine Ausnahme auslöst, wird eine neue HealthReportEntry-Struktur zurückgegeben, bei der die Eigenschaft HealthReportEntry.Status, die von AddCheck definiert wird, auf FailureStatus festgelegt ist (vgl. Abschnitt Registrieren von Integritätsprüfungsdiensten) und die die innere Ausnahme enthält, die den Überprüfungsfehler ursprünglich verursacht hat. Description ist auf die Meldung der Ausnahme festgelegt.

Registrieren von Integritätsprüfungsdiensten

Der ExampleHealthCheck-Typ wird mit AddCheck in Startup.ConfigureServices den Integritätsprüfungsdiensten hinzugefügt:

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

Die in der folgenden Abbildung gezeigte AddCheck-Überladung legt den Fehlerstatus (HealthStatus) fest, der angegeben werden soll, wenn die Integritätsprüfung einen Fehler meldet. Wenn der Fehlerstatus auf null (Standardwert) festgelegt ist, wird HealthStatus.Unhealthy gemeldet. Diese Überladung ist ein nützliches Szenario für Bibliotheksersteller: Bei einem Integritätsprüfungsfehler wird der durch die Bibliothek angegebene Fehlerstatus von der App erzwungen, wenn die Implementierung der Integritätsprüfung die Einstellung berücksichtigt.

Tags können zum Filtern von Integritätsprüfungen verwendet werden (dies wird im Abschnitt Filtern von Integritätsprüfungen genauer beschrieben).

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

AddCheck kann auch eine Lambdafunktion ausführen. Im folgenden Beispiel wird der Name der Integritätsprüfung als Example angegeben, und die Prüfung gibt immer einen fehlerfreien Status zurück:

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

Rufen Sie AddTypeActivatedCheck auf, um Argumente an die Implementierung einer Integritätsprüfung zu übergeben. Im folgenden Beispiel akzeptiert TestHealthCheckWithArgs eine ganze Zahl und eine Zeichenfolge, wenn CheckHealthAsync aufgerufen wird:

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 wird durch Aufrufen von AddTypeActivatedCheck mit der Übergabe der ganzen Zahl und der Zeichenfolge an die Implementierung registriert:

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

Verwenden von Integritätsprüfungsrouting

Rufen Sie in Startup.Configure auf der Endpunkterstellung mit der Endpunkt-URL oder dem relativen Pfad MapHealthChecks auf:

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

Anfordern des Hosts

Rufen Sie RequireHost auf, um einen oder mehrere zugelassene Hosts für den Integritätsprüfungs-Endpunkt anzugeben. Hosts sollten Unicode anstelle von Punycode verwenden und können einen Port enthalten. Wenn keine Sammlung bereitgestellt wird, wird jeder Host akzeptiert.

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

Weitere Informationen finden Sie im Abschnitt Filtern nach Port.

Anfordern der Autorisierung

Rufen Sie RequireAuthorization auf, um die Autorisierungsmiddleware auf dem Integritätsprüfungs-Anforderungsendpunkt auszuführen. Eine RequireAuthorization-Überladung akzeptiert eine oder mehrere Autorisierungsrichtlinien. Wenn keine Richtlinie bereitgestellt wird, wird die standardmäßige Autorisierungsrichtlinie verwendet.

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

Aktivieren ursprungsübergreifender Anforderungen (CORS)

Obwohl das manuelle Ausführen von Integritätsprüfungen über einen Browser kein gängiges Szenario ist, kann CORS-Middleware durch Aufrufen von RequireCors für Integritätsprüfungsendpunkte aktiviert werden. Eine RequireCors-Überladung akzeptiert einen CORS-Richtliniengenerator-Delegaten (CorsPolicyBuilder) oder einen Richtliniennamen. Wenn keine Richtlinie bereitgestellt wird, wird die standardmäßige CORS-Richtlinie verwendet. Weitere Informationen finden Sie unter Aktivieren ursprungsübergreifender Anforderungen (Cross-Origin Requests, CORS) in ASP.NET Core.

Optionen für die Integritätsprüfung

HealthCheckOptions ermöglichen die Anpassung des Verhaltens von Integritätsprüfungen:

Filtern von Integritätsprüfungen

Standardmäßig führt die Middleware für Integritätsprüfungen alle registrierten Integritätsprüfungen aus. Um eine Teilmenge von Integritätsprüfungen auszuführen, stellen Sie eine Funktion bereit, die einen booleschen Wert an die Option Predicate zurückgibt. Im folgenden Beispiel wird die Bar-Integritätsprüfung anhand ihres Tags (bar_tag) in der Bedingungsanweisung der Funktion herausgefiltert. Dabei wird true nur zurückgegeben, wenn die Tags-Eigenschaft der Integritätsprüfung mit foo_tag oder baz_tag übereinstimmt:

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.Configure filtert Predicate die „Bar“-Integritätsprüfung heraus. Nur Foo und Baz werden ausgeführt:

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

Anpassen des HTTP-Statuscodes

Verwenden Sie ResultStatusCodes, um die Zuordnung des Integritätsstatus zu HTTP-Statuscodes anzupassen. Die folgenden StatusCodes-Zuweisungen stellen die von der Middleware verwendeten Standardwerte dar. Ändern Sie die Statuscodewerte so, dass sie Ihren Anforderungen entsprechen.

In Startup.Configure:

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

Unterdrücken von Cacheheadern

AllowCachingResponses steuert, ob die Middleware für Integritätsprüfungen einer Testantwort HTTP-Header hinzufügt, um das Zwischenspeichern von Antworten zu verhindern. Wenn der Wert false (Standard) lautet, legt die Middleware die Header Cache-Control, Expires und Pragma fest oder überschreibt sie, um eine Zwischenspeicherung der Antworten zu verhindern. Wenn der Wert true lautet, ändert die Middleware die Cacheheader der Antwort nicht.

In Startup.Configure:

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

Anpassen der Ausgabe

Legen Sie in Startup.Configure die Option HealthCheckOptions.ResponseWriter auf einen Delegaten für das Schreiben der Antwort fest:

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

Der Standarddelegat schreibt eine minimale Klartextantwort mit dem Zeichenfolgenwert HealthReport.Status. Der folgende benutzerdefinierte Delegat gibt eine benutzerdefinierte JSON-Antwort aus.

Das erste Beispiel aus der Beispiel-App veranschaulicht die Verwendung von 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);
    }
}

Im zweiten Beispiel wird veranschaulicht, wie Newtonsoft.Json verwendet wird:

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));
}

Kommentieren Sie in der Beispiel-App die PräprozessoranweisungSYSTEM_TEXT_JSON in CustomWriterStartup.cs aus, um die Newtonsoft.Json-Version von WriteResponse zu aktivieren.

Die Integritätsprüfungs-API bietet keine integrierte Unterstützung für komplexe JSON-Rückgabeformate, da das Format für Ihre Überwachungssystemauswahl spezifisch ist. Passen Sie die Antwort in den vorangehenden Beispielen nach Bedarf an. Weitere Informationen zur JSON-Serialisierung mit System.Text.Json finden Sie unter Serialisieren und Deserialisieren von JSON in .NET.

Datenbanktest

Eine Integritätsprüfung kann eine Datenbankabfrage angeben, die als boolescher Test ausgeführt wird, um zu ermitteln, ob die Datenbank normal reagiert.

Die Beispiel-App verwendet AspNetCore.Diagnostics.HealthChecks, eine Bibliothek für Integritätsprüfungen für ASP.NET Core-Apps, um eine Integritätsprüfung für eine SQL Server-Datenbank-Instanz auszuführen. AspNetCore.Diagnostics.HealthChecks führt eine SELECT 1-Abfrage in der Datenbank aus, um zu bestätigen, dass die Verbindung mit der Datenbank fehlerfrei ist.

Warnung

Wenn Sie die Datenbankverbindung mithilfe einer Abfrage überprüfen, wählen Sie eine Abfrage aus, die eine schnelle Antwort zurückgibt. Bei einer Abfrage besteht immer das Risiko, dass die Datenbank überladen und ihre Leistung beeinträchtigt wird. In den meisten Fällen ist es nicht notwendig, eine Testabfrage auszuführen. Es genügt zumeist, einfach erfolgreich eine Verbindung mit der Datenbank herzustellen. Wenn Sie eine Abfrage ausführen müssen, wählen Sie eine einfache SELECT-Abfrage aus, wie z.B. SELECT 1.

Fügen Sie einen Paketverweis auf AspNetCore.HealthChecks.SqlServer hinzu.

Geben Sie in der appsettings.json -Datei der App eine gültige Zeichenfolge für die Datenbankverbindung an. Die App verwendet eine SQL Server-Datenbank namens 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": "*"
}

Registrieren Sie Integritätsprüfungsdienste mit AddHealthChecks in Startup.ConfigureServices. Die Beispiel-App ruft die AddSqlServer-Methode mit der Verbindungszeichenfolge der Datenbank (DbHealthStartup.cs) auf:

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

Ein Integritätsprüfungs-Endpunkt wird durch Aufrufen von MapHealthChecks in Startup.Configure erstellt:

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

Um das Szenario für den Datenbanktest mithilfe der Beispiel-App auszuführen, verwenden Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell:

dotnet run --scenario db

Hinweis

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Entity Framework Core-DbContext-Test

Die DbContext-Überprüfung bestätigt, dass die App mit der Datenbank kommunizieren kann, die für einen EF Core-DbContext konfiguriert wurde. Die DbContext Überprüfung wird in Apps unterstützt, für die gilt:

AddDbContextCheck<TContext> registriert eine Integritätsprüfung für einen DbContext. Der DbContext wird als der TContext für die Methode bereitgestellt. Eine Überladung ist verfügbar, um den Fehlerstatus, Tags sowie eine benutzerdefinierte Testabfrage zu konfigurieren.

Standardmäßig:

  • Der DbContextHealthCheck ruft die CanConnectAsync-Methode von EF Core auf. Sie können festlegen, welcher Vorgang ausgeführt wird, wenn die Integrität mit AddDbContextCheck-Methodenüberladungen überprüft wird.
  • Der Name der Integritätsprüfung ist der Name des TContext-Typs.

In der Beispiel-App wird AppDbContext für AddDbContextCheck bereitgestellt und als Dienst in Startup.ConfigureServices (DbContextHealthStartup.cs) registriert:

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

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

Ein Integritätsprüfungs-Endpunkt wird durch Aufrufen von MapHealthChecks in Startup.Configure erstellt:

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

Stellen Sie sicher, dass die mit der Verbindungszeichenfolge angegebene Datenbank in der SQL Server-Instanz nicht vorhanden ist, um das DbContext-Testszenario mithilfe der Beispiel-App ausführen zu können. Falls die Datenbank vorhanden ist, löschen Sie sie.

Führen Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell aus:

dotnet run --scenario dbcontext

Wenn die App ausgeführt wird, überprüfen Sie den Integritätsstatus, indem Sie in einem Browser eine Anforderung an den /health-Endpunkt senden. Datenbank und AppDbContext sind nicht vorhanden, also sendet die App die folgende Antwort:

Unhealthy

Fordern Sie die Beispiel-App auf, die Datenbank zu erstellen. Senden Sie eine /createdatabase-Anforderung. Die App sendet die folgende Antwort:

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

Senden Sie eine Anforderung an den /health-Endpunkt. Datenbank und Kontext sind vorhanden, also sendet die App die folgende Antwort:

Healthy

Fordern Sie die Beispiel-App auf, die Datenbank zu löschen. Senden Sie eine /deletedatabase-Anforderung. Die App sendet die folgende Antwort:

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

Senden Sie eine Anforderung an den /health-Endpunkt. Die App meldet einen fehlerhaften Status:

Unhealthy

Separate Tests für Bereitschaft und Lebendigkeit

In einigen Hostingszenarien wird ein Integritätsprüfungspaar verwendet, mit dem zwischen zwei App-Status unterschieden wird:

  • Bereitschaft gibt an, ob die App ordnungsgemäß ausgeführt wird, aber nicht für den Empfang von Anforderungen bereit ist.
  • Livetest gibt an, ob eine App abgestürzt ist und neu gestartet werden muss.

Betrachten Sie das folgende Beispiel: Eine App muss eine große Konfigurationsdatei herunterladen, bevor sie für die Verarbeitung von Anforderungen bereit ist. Wir möchten nicht, dass die App neu gestartet wird, wenn der erste Download fehlschlägt, da die App mehrmals versuchen kann, die Datei herunterzuladen. Wir verwenden einen Livetest, um den Livezustand des Prozesses zu beschreiben. Weitere Überprüfungen erfolgen nicht. Außerdem soll verhindert werden, dass Anforderungen an die App gesendet werden, bevor die Konfigurationsdatei erfolgreich heruntergeladen wurde. Wir verwenden einen Bereitschaftstest, um den Status "nicht bereit" anzugeben, bis der Download erfolgreich durchgeführt wurde und die App für den Empfang von Anforderungen bereit ist.

Die Beispiel-App enthält eine Integritätsprüfung, um den Abschluss eines Starttasks mit langer Ausführungsdauer in einem gehosteten Dienst zu melden. StartupHostedServiceHealthCheck macht die Eigenschaft StartupTaskCompleted verfügbar, die der gehostete Dienst auf true festlegen kann, wenn der Task mit langer Ausführungsdauer abgeschlossen ist (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."));
    }
}

Der Hintergrundtask mit langer Ausführungsdauer wird von einem gehosteten Dienst (Services/StartupHostedService) gestartet. Nach Abschluss des Tasks wird StartupHostedServiceHealthCheck.StartupTaskCompleted auf true festgelegt:

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()
    {
    }
}

Die Integritätsprüfung wird mit AddCheck zusammen mit dem gehosteten Dienst in Startup.ConfigureServices registriert. Da der gehostete Dienst die Eigenschaft in der Integritätsprüfung festlegen muss, wird die Integritätsprüfung ebenfalls im Dienstcontainer (LivenessProbeStartup.cs) registriert:

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>();

Ein Integritätsprüfungs-Endpunkt wird durch Aufrufen von MapHealthChecks in Startup.Configure erstellt. In der Beispiel-App wird der Integritätsprüfungs-Endpunkt erstellt unter:

  • /health/ready für die Bereitschaftsprüfung. Die Bereitschaftsprüfung filtert auf Integritätsprüfungen mit dem ready-Tag.
  • /health/live für die Lebendigkeitsprüfung. Die Lebendigkeitsprüfung filtert StartupHostedServiceHealthCheck durch Rückgabe von false in HealthCheckOptions.Predicate heraus (weitere Informationen unter Filtern von Integritätsprüfungen).

Im folgenden Beispielcode gilt Folgendes:

  • Die Bereitschaftsprüfung verwendet alle registrierten Überprüfungen mit dem Tag „Bereit“.
  • Predicate schließt alle Überprüfungen aus und gibt 200-OK zurück.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

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

Um das Szenario für die Konfiguration von Bereitschafts-/Lebendigkeitsprüfungen mithilfe der Beispiel-App auszuführen, verwenden Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell:

dotnet run --scenario liveness

Besuchen Sie /health/ready mehrmals in einem Browser, bis 15 Sekunden verstrichen sind. Die Integritätsprüfung meldet während der ersten 15 Sekunden Unhealthy. Nach 15 Sekunden meldet der Endpunkt Healthy, was darauf hindeutet, dass die Ausführung des Tasks mit langer Ausführungsdauer durch den gehosteten Dienst abgeschlossen wurde.

In diesem Beispiel wird auch ein Integritätsprüfungsherausgeber erstellt (IHealthCheckPublisher-Implementierung), der die erste Bereitschaftsprüfung mit einer Verzögerung von zwei Sekunden ausführt. Weitere Informationen finden Sie im Abschnitt Herausgeber der Integritätsprüfung.

Kubernetes-Beispiel

Die Verwendung von Bereitschafts- und Lebendigkeitstests ist in Umgebungen wie Kubernetes sehr nützlich. In Kubernetes muss eine App möglicherweise zeitaufwendige Startaufgaben ausführen, bevor sie Anforderungen wie z. B. das Testen der Verfügbarkeit der zugrunde liegenden Datenbank erfüllt. Durch Verwendung separater Überprüfungen kann der Orchestrator unterscheiden, ob eine App funktioniert, aber noch nicht bereit ist, oder ob die App nicht gestartet wurde. Weitere Informationen zu Bereitschafts- und Lebendigkeitstests in Kubernetes finden Sie in der Kubernetes-Dokumentation unter Configure Liveness and Readiness Probes (Konfigurieren von Lebendigkeits- und Bereitschaftstests).

Das folgende Beispiel veranschaulicht die Konfiguration eines Bereitschaftstests in 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

Metrikbasierter Test mit einem benutzerdefinierten Antwortwriter

Die Beispiel-App veranschaulicht eine Arbeitsspeicher-Integritätsprüfung mit einem benutzerdefinierten Antwortwriter.

MemoryHealthCheck meldet einen beeinträchtigten Status, wenn die App mehr Arbeitsspeicher verwendet, als für den Schwellenwert festgelegt wurde (1 GB in der Beispiel-App). Das HealthCheckResult enthält Garbage Collector-Informationen (GC) für die 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));
    }
}

Registrieren Sie Integritätsprüfungsdienste mit AddHealthChecks in Startup.ConfigureServices. Die Integritätsprüfung wird nicht durch Übergabe an AddCheck aktiviert, stattdessen wird MemoryHealthCheck als Dienst registriert. Alle bei IHealthCheck registrierten Dienste stehen für die Dienste und Middleware für Integritätsprüfungen zur Verfügung. Es wird empfohlen, Integritätsprüfungsdienste als Singleton-Dienste zu registrieren.

In CustomWriterStartup.cs der Beispiel-App:

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

Ein Integritätsprüfungs-Endpunkt wird durch Aufrufen von MapHealthChecks in Startup.Configure erstellt. Ein WriteResponse-Delegat wird in der ResponseWriter-Eigenschaft angegeben, um eine benutzerdefinierte JSON-Antwort auszugeben, wenn die Integritätsprüfung ausgeführt wird:

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

Der WriteResponse-Delegat formatiert das CompositeHealthCheckResult als JSON-Objekt und führt zu folgender JSON-Ausgabe für die Integritätsprüfungsantwort. Weitere Informationen finden Sie im Abschnitt Anpassen der Ausgabe.

Um den metrikbasierten Test mit benutzerdefinierter Ausgabe des Antwortwriters mithilfe der Beispiel-App auszuführen, verwenden Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell:

dotnet run --scenario writer

Hinweis

AspNetCore.Diagnostics.HealthChecks enthält Szenarios für metrikbasierte Integritätsprüfungen, einschließlich Prüfungen des Datenträgerspeichers und Lebendigkeitsprüfungen mit Maximalwert.

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Filtern nach Port

Rufen Sie RequireHost auf MapHealthChecks mit einem URL-Muster auf, das einen Port angibt, um die an diesen Port gerichteten Integritätsprüfungsanforderungen einzuschränken. Dieser Ansatz wird normalerweise in einer Containerumgebung verfolgt, um einen Port für Überwachungsdienste verfügbar zu machen.

Die Beispiel-App konfiguriert den Port mithilfe des Umgebungsvariablen-Konfigurationsanbieters. Der Port wird in der Datei launchSettings.json festgelegt und über eine Umgebungsvariable an den Konfigurationsanbieter übergeben. Sie müssen den Server auch so konfigurieren, dass er am Verwaltungsport auf Anforderungen lauscht.

Um die Beispiel-App zum Veranschaulichen der Konfiguration des Verwaltungsports zu verwenden, erstellen Sie die Datei launchSettings.json in einem Properties-Ordner.

Die folgende Properties/launchSettings.json-Datei in der Beispiel-App ist in den Projektdateien der Beispiel-App nicht vorhanden und muss manuell erstellt werden:

{
  "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/"
    }
  }
}

Registrieren Sie Integritätsprüfungsdienste mit AddHealthChecks in Startup.ConfigureServices. Erstellen Sie einen Integritätsprüfungs-Endpunkt durch Aufrufen von MapHealthChecks in Startup.Configure.

In der Beispiel-App gibt ein Aufruf von RequireHost auf dem Endpunkt in Startup.Configure den Verwaltungsport aus der Konfiguration an:

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

Endpunkte werden in der Beispiel-App in Startup.Configure erstellt. Im folgenden Beispielcode gilt Folgendes:

  • Die Bereitschaftsprüfung verwendet alle registrierten Überprüfungen mit dem Tag „Bereit“.
  • Predicate schließt alle Überprüfungen aus und gibt 200-OK zurück.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

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

Hinweis

Sie können vermeiden, die Datei launchSettings.json in der Beispiel-App erstellen zu müssen, indem Sie den Verwaltungsport explizit im Code festlegen. Fügen Sie in Program.cs an der Stelle, an der HostBuilder erstellt wird, einen Aufruf von ListenAnyIP hinzu, und geben Sie den Endpunkt des Verwaltungsports der App an. Geben Sie in Configure von ManagementPortStartup.cs den Verwaltungsport mit RequireHost an:

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");
});

Um das Szenario für die Konfiguration des Verwaltungsports mithilfe der Beispiel-App auszuführen, verwenden Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell:

dotnet run --scenario port

Verteilen einer Integritätsprüfungsbibliothek

So verteilen Sie eine Integritätsprüfung als Bibliothek:

  1. Schreiben Sie eine Integritätsprüfung, die die IHealthCheck-Schnittstelle als eigenständige Klasse implementiert. Die Klasse kann Abhängigkeitsinjektion (Dependency Injection, DI), Typaktivierung und benannte Optionen verwenden, um auf Konfigurationsdaten zuzugreifen.

    In der Integritätsprüfungslogik von CheckHealthAsync gilt Folgendes:

    • data1 und data2 werden in der Methode verwendet, um die Integritätsprüfungslogik des Tests auszuführen.
    • AccessViolationException wird verarbeitet.

    Wenn eine AccessViolationException auftritt, wird der FailureStatus mit dem HealthCheckResult zurückgegeben, damit Benutzer den Integritätsprüfungs-Fehlerstatus konfigurieren können.

    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. Schreiben Sie eine Erweiterungsmethode mit Parametern, die von der nutzenden App in ihrer Startup.Configure-Methode aufgerufen werden. Nehmen Sie im folgenden Beispiel die folgende Signatur für die Integritätsprüfungsmethode an:

    ExampleHealthCheck(string, string, int )
    

    Die oben stehende Signatur gibt an, dass ExampleHealthCheck weitere Daten benötigt, um die Testlogik für die Integritätsprüfung zu verarbeiten. Die Daten werden für den Delegaten bereitgestellt, der zum Erstellen der Integritätsprüfungsinstanz verwendet wird, wenn die Integritätsprüfung bei einer Erweiterungsmethode registriert wird. Im folgenden Beispiel gibt der Aufrufer optional Folgendes an:

    • Name der Integritätsprüfung (name). Wenn der Wert null ist, wird example_health_check verwendet.
    • string-Datenpunkt für die Integritätsprüfung (data1).
    • integer-Datenpunkt für die Integritätsprüfung (data2). Wenn der Wert null ist, wird 1 verwendet.
    • Fehlerstatus (HealthStatus). Der Standardwert ist null. Wenn der Wert null ist, wird HealthStatus.Unhealthy für einen Fehlerstatus gemeldet.
    • Tags (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));
        }
    }
    

Herausgeber der Integritätsprüfung

Wenn dem Dienstcontainer ein IHealthCheckPublisher hinzugefügt wird, führt das Integritätsprüfungssystem Ihre Integritätsprüfungen regelmäßig aus und ruft PublishAsync mit dem Ergebnis auf. Dies ist nützlich in einem Szenario mit pushbasiertem Integritätsüberwachungssystem, in dem jeder Prozess das Überwachungssystem regelmäßig aufrufen muss, um die Integrität zu bestimmen.

Die IHealthCheckPublisher-Schnittstelle weist eine einzige Methode auf:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions ermöglichen Ihnen, Folgendes festzulegen:

  • Delay: Hierbei handelt es sich um die angewendete anfängliche Verzögerung zwischen dem Start der App und der Ausführung von IHealthCheckPublisher-Instanzen. Die Verzögerung wird einmal beim Start angewendet und gilt nicht für die nachfolgenden Iterationen. Der Standardwert beträgt fünf Sekunden.
  • Period: Hierbei handelt es sich um die Dauer der Ausführung von IHealthCheckPublisher. Der Standardwert ist 30 Sekunden.
  • Predicate: Wenn der Wert für Predicatenull ist (Standard), führt der Veröffentlichungsdienst für die Integritätsprüfung alle registrierten Integritätsprüfungen durch. Um eine Teilmenge von Integritätsprüfungen auszuführen, stellen Sie eine Funktion bereit, die die Menge der Prüfungen filtert. Das Prädikat wird in jedem Zeitraum ausgewertet.
  • Timeout: Hierbei handelt es sich um das Zeitlimit für die Ausführung der Integritätsprüfungen für alle IHealthCheckPublisher-Instanzen. Verwenden Sie InfiniteTimeSpan zur Ausführung ohne Timeout. Der Standardwert ist 30 Sekunden.

In der Beispiel-App ist ReadinessPublisher eine IHealthCheckPublisher-Implementierung. Der Integritätsprüfungsstatus wird für jede Überprüfung auf folgenden Protokollebenen protokolliert:

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;
    }
}

Im Beispiel LivenessProbeStartup der Beispiel-App StartupHostedService hat die Bereitschaftsprüfung eine Startverzögerung von zwei Sekunden und führt die Prüfung alle 30 Sekunden aus. Zum Aktivieren der IHealthCheckPublisher Implementierung registriert das Beispiel ReadinessPublisher als Singletondienst im Abhängigkeitsinjektionscontainer (Dependency Injection, DI):

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>();

Hinweis

AspNetCore.Diagnostics.HealthChecks enthält Herausgeber für verschiedene Systeme, einschließlich Application Insights.

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Einschränken von Integritätsprüfungen mit MapWhen

Verwenden Sie MapWhen, um die Anforderungspipeline für Endpunkte von Integritätsprüfungen bedingt zu branchen.

Im folgenden Beispiel verzweigt MapWhen die Anforderungspipeline so, dass die Middleware für Integritätsprüfungen aktiviert wird, wenn eine GET-Anforderung für den Endpunkt api/HealthCheck empfangen wird:

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

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

Weitere Informationen finden Sie unter ASP.NET Core-Middleware.

ASP.NET Core bietet Middleware für Integritätsprüfungen und Bibliotheken für die Berichterstellung für Komponenten der App-Infrastruktur.

Integritätsprüfungen werden von einer App als HTTP-Endpunkte verfügbar gemacht. Endpunkte für die Integritätsprüfung können für verschiedene Echtzeitüberwachungsszenarien konfiguriert werden:

  • Integritätstests können von Containerorchestratoren und Lastenausgleichsmodulen verwendet werden, um den Status einer App zu überprüfen. Ein Containerorchestrator kann z.B. auf eine fehlerhafte Integritätsprüfung reagieren, indem die Ausführung einer Bereitstellung angehalten oder ein Container neu gestartet wird. Ein Lastenausgleichsmodul kann auf eine fehlerhafte App reagieren, indem Datenverkehr von der fehlerhaften zu einer fehlerfreien Instanz umgeleitet wird.
  • Die Nutzung von Arbeitsspeicher, Datenträgern und anderen physischen Serverressourcen kann auf einen fehlerfreien Status überwacht werden.
  • Integritätsprüfungen können die Abhängigkeiten einer App testen, wie z.B. Datenbanken und externe Dienstendpunkte, um Verfügbarkeit und normale Funktionsweise zu bestätigen.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Die Beispiel-App enthält Beispiele der in diesem Artikel beschriebenen Szenarien. Um die Beispiel-App für ein bestimmtes Szenario auszuführen, verwenden Sie den Befehl dotnet run aus dem Ordner des Projekts in einer Befehlsshell. Informationen zur Verwendung der Beispiel-App finden Sie in der zugehörigen Datei README.md und den Szenariobeschreibungen in diesem Artikel.

Voraussetzungen

Integritätsprüfungen werden in der Regel mit einem externen Überwachungsdienst oder Containerorchestrator verwendet, um den Status einer App zu überprüfen. Bevor Sie Integritätsprüfungen zu einer App hinzufügen, entscheiden Sie, welches Überwachungssystem verwendet werden soll. Das Überwachungssystem bestimmt, welche Arten von Integritätsprüfungen erstellt und wie die jeweiligen Endpunkte konfiguriert werden müssen.

Für ASP.NET Core-Apps wird implizit auf das Paket Microsoft.AspNetCore.Diagnostics.HealthChecks verwiesen. Fügen Sie einen Verweis auf das Paket Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore hinzu, um Integritätsprüfungen mit Entity Framework Core durchzuführen.

Die Beispiel-App stellt Startcode bereit, um die Integritätsprüfungen für verschiedene Szenarien zu veranschaulichen. Das Szenario Datenbanktest überprüft die Integrität einer Datenbankverbindung mithilfe von AspNetCore.Diagnostics.HealthChecks. Im Szenario DbContext-Test wird eine Datenbank mithilfe eines EF Core-DbContext überprüft. Für ein Erkunden der Datenbankszenarios gilt für die Beispiel-App:

Hinweis

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Ein anderes Szenario für Integritätsprüfungen zeigt, wie Sie Integritätsprüfungen auf einen Verwaltungsport filtern können. Für die Beispiel-App müssen Sie eine Properties/launchSettings.json-Datei erstellen, die die Verwaltungs-URL und den Verwaltungsport enthält. Weitere Informationen finden Sie im Abschnitt Filtern nach Port.

Grundlegender Integritätstest

In vielen Apps genügt zur Ermittlung des App-Status eine grundlegende Integritätstestkonfiguration, die die Verfügbarkeit der App für die Verarbeitung von Anforderungen (Lebendigkeit) meldet.

Die grundlegende Konfiguration registriert Integritätsprüfungsdienste und ruft die Middleware für Integritätsprüfungen auf, damit diese an einem URL-Endpunkt mit dem Integritätsstatus antwortet. Standardmäßig werden keine spezifischen Integritätsprüfungen registriert, um eine bestimmte Abhängigkeit oder ein bestimmtes Subsystem zu testen. Die App wird als fehlerfrei angesehen, wenn sie an der URL des Integritätsendpunkts antworten kann. Der standardmäßig verwendete Antwortwriter schreibt den Status (HealthStatus) als Nur-Text-Antwort zurück an den Client und gibt dabei den Status HealthStatus.Healthy, HealthStatus.Degraded oder HealthStatus.Unhealthy an.

Registrieren Sie Integritätsprüfungsdienste mit AddHealthChecks in Startup.ConfigureServices. Erstellen Sie einen Integritätsprüfungs-Endpunkt durch Aufrufen von MapHealthChecks in Startup.Configure.

In der Beispiel-App wird der Integritätsprüfungs-Endpunkt in /health (BasicStartup.cs) erstellt:

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

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

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

Um das Szenario für die grundlegende Konfiguration mithilfe der Beispiel-App auszuführen, verwenden Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell:

dotnet run --scenario basic

Docker-Beispiel

Docker bietet eine integrierte HEALTHCHECK-Direktive, mit der Sie den Status einer App überprüfen können, die die grundlegende Konfiguration für Integritätsprüfungen verwendet:

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

Erstellen von Integritätsprüfungen

Integritätsprüfungen werden durch Implementieren der IHealthCheck-Schnittstelle erstellt. Die CheckHealthAsync-Methode gibt ein HealthCheckResult zurück, das die Integrität als Healthy, Degraded oder Unhealthy angibt. Das Ergebnis wird als Klartextantwort mit einem konfigurierbaren Statuscode geschrieben (diese Konfiguration wird im Abschnitt Optionen für die Integritätsprüfung beschrieben). HealthCheckResult kann auch optionale Schlüssel-Wert-Paare zurückgeben.

Die folgende ExampleHealthCheck-Klasse veranschaulicht das Layout einer Integritätsprüfung. Die Integritätsprüfungslogik wird in der CheckHealthAsync-Methode platziert. Im folgenden Beispiel wird eine Dummyvariable healthCheckResultHealthy auf true festgelegt. Wenn der Wert von healthCheckResultHealthy auf false festgelegt ist, wird der HealthCheckResult.Unhealthy-Status zurückgegeben.

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."));
    }
}

Registrieren von Integritätsprüfungsdiensten

Der ExampleHealthCheck-Typ wird mit AddCheck in Startup.ConfigureServices den Integritätsprüfungsdiensten hinzugefügt:

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

Die in der folgenden Abbildung gezeigte AddCheck-Überladung legt den Fehlerstatus (HealthStatus) fest, der angegeben werden soll, wenn die Integritätsprüfung einen Fehler meldet. Wenn der Fehlerstatus auf null (Standardwert) festgelegt ist, wird HealthStatus.Unhealthy gemeldet. Diese Überladung ist ein nützliches Szenario für Bibliotheksersteller: Bei einem Integritätsprüfungsfehler wird der durch die Bibliothek angegebene Fehlerstatus von der App erzwungen, wenn die Implementierung der Integritätsprüfung die Einstellung berücksichtigt.

Tags können zum Filtern von Integritätsprüfungen verwendet werden (dies wird im Abschnitt Filtern von Integritätsprüfungen genauer beschrieben).

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

AddCheck kann auch eine Lambdafunktion ausführen. Im folgenden Beispiel wird der Name der Integritätsprüfung als Example angegeben, und die Prüfung gibt immer einen fehlerfreien Status zurück:

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

Rufen Sie AddTypeActivatedCheck auf, um Argumente an die Implementierung einer Integritätsprüfung zu übergeben. Im folgenden Beispiel akzeptiert TestHealthCheckWithArgs eine ganze Zahl und eine Zeichenfolge, wenn CheckHealthAsync aufgerufen wird:

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 wird durch Aufrufen von AddTypeActivatedCheck mit der Übergabe der ganzen Zahl und der Zeichenfolge an die Implementierung registriert:

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

Verwenden von Integritätsprüfungsrouting

Rufen Sie in Startup.Configure auf der Endpunkterstellung mit der Endpunkt-URL oder dem relativen Pfad MapHealthChecks auf:

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

Anfordern des Hosts

Rufen Sie RequireHost auf, um einen oder mehrere zugelassene Hosts für den Integritätsprüfungs-Endpunkt anzugeben. Hosts sollten Unicode anstelle von Punycode verwenden und können einen Port enthalten. Wenn keine Sammlung bereitgestellt wird, wird jeder Host akzeptiert.

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

Weitere Informationen finden Sie im Abschnitt Filtern nach Port.

Anfordern der Autorisierung

Rufen Sie RequireAuthorization auf, um die Autorisierungsmiddleware auf dem Integritätsprüfungs-Anforderungsendpunkt auszuführen. Eine RequireAuthorization-Überladung akzeptiert eine oder mehrere Autorisierungsrichtlinien. Wenn keine Richtlinie bereitgestellt wird, wird die standardmäßige Autorisierungsrichtlinie verwendet.

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

Aktivieren ursprungsübergreifender Anforderungen (CORS)

Obwohl das manuelle Ausführen von Integritätsprüfungen über einen Browser kein gängiges Szenario ist, kann CORS-Middleware durch Aufrufen von RequireCors für Integritätsprüfungsendpunkte aktiviert werden. Eine RequireCors-Überladung akzeptiert einen CORS-Richtliniengenerator-Delegaten (CorsPolicyBuilder) oder einen Richtliniennamen. Wenn keine Richtlinie bereitgestellt wird, wird die standardmäßige CORS-Richtlinie verwendet. Weitere Informationen finden Sie unter Aktivieren ursprungsübergreifender Anforderungen (Cross-Origin Requests, CORS) in ASP.NET Core.

Optionen für die Integritätsprüfung

HealthCheckOptions ermöglichen die Anpassung des Verhaltens von Integritätsprüfungen:

Filtern von Integritätsprüfungen

Standardmäßig führt die Middleware für Integritätsprüfungen alle registrierten Integritätsprüfungen aus. Um eine Teilmenge von Integritätsprüfungen auszuführen, stellen Sie eine Funktion bereit, die einen booleschen Wert an die Option Predicate zurückgibt. Im folgenden Beispiel wird die Bar-Integritätsprüfung anhand ihres Tags (bar_tag) in der Bedingungsanweisung der Funktion herausgefiltert. Dabei wird true nur zurückgegeben, wenn die Tags-Eigenschaft der Integritätsprüfung mit foo_tag oder baz_tag übereinstimmt:

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.Configure filtert Predicate die „Bar“-Integritätsprüfung heraus. Nur Foo und Baz werden ausgeführt:

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

Anpassen des HTTP-Statuscodes

Verwenden Sie ResultStatusCodes, um die Zuordnung des Integritätsstatus zu HTTP-Statuscodes anzupassen. Die folgenden StatusCodes-Zuweisungen stellen die von der Middleware verwendeten Standardwerte dar. Ändern Sie die Statuscodewerte so, dass sie Ihren Anforderungen entsprechen.

In Startup.Configure:

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

Unterdrücken von Cacheheadern

AllowCachingResponses steuert, ob die Middleware für Integritätsprüfungen einer Testantwort HTTP-Header hinzufügt, um das Zwischenspeichern von Antworten zu verhindern. Wenn der Wert false (Standard) lautet, legt die Middleware die Header Cache-Control, Expires und Pragma fest oder überschreibt sie, um eine Zwischenspeicherung der Antworten zu verhindern. Wenn der Wert true lautet, ändert die Middleware die Cacheheader der Antwort nicht.

In Startup.Configure:

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

Anpassen der Ausgabe

Legen Sie in Startup.Configure die Option HealthCheckOptions.ResponseWriter auf einen Delegaten für das Schreiben der Antwort fest:

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

Der Standarddelegat schreibt eine minimale Klartextantwort mit dem Zeichenfolgenwert HealthReport.Status. Der folgende benutzerdefinierte Delegat gibt eine benutzerdefinierte JSON-Antwort aus.

Das erste Beispiel aus der Beispiel-App veranschaulicht die Verwendung von 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);
    }
}

Im zweiten Beispiel wird veranschaulicht, wie Newtonsoft.Json verwendet wird:

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));
}

Kommentieren Sie in der Beispiel-App die PräprozessoranweisungSYSTEM_TEXT_JSON in CustomWriterStartup.cs aus, um die Newtonsoft.Json-Version von WriteResponse zu aktivieren.

Die Integritätsprüfungs-API bietet keine integrierte Unterstützung für komplexe JSON-Rückgabeformate, da das Format für Ihre Überwachungssystemauswahl spezifisch ist. Passen Sie die Antwort in den vorangehenden Beispielen nach Bedarf an. Weitere Informationen zur JSON-Serialisierung mit System.Text.Json finden Sie unter Serialisieren und Deserialisieren von JSON in .NET.

Datenbanktest

Eine Integritätsprüfung kann eine Datenbankabfrage angeben, die als boolescher Test ausgeführt wird, um zu ermitteln, ob die Datenbank normal reagiert.

Die Beispiel-App verwendet AspNetCore.Diagnostics.HealthChecks, eine Bibliothek für Integritätsprüfungen für ASP.NET Core-Apps, um eine Integritätsprüfung für eine SQL Server-Datenbank-Instanz auszuführen. AspNetCore.Diagnostics.HealthChecks führt eine SELECT 1-Abfrage in der Datenbank aus, um zu bestätigen, dass die Verbindung mit der Datenbank fehlerfrei ist.

Warnung

Wenn Sie die Datenbankverbindung mithilfe einer Abfrage überprüfen, wählen Sie eine Abfrage aus, die eine schnelle Antwort zurückgibt. Bei einer Abfrage besteht immer das Risiko, dass die Datenbank überladen und ihre Leistung beeinträchtigt wird. In den meisten Fällen ist es nicht notwendig, eine Testabfrage auszuführen. Es genügt zumeist, einfach erfolgreich eine Verbindung mit der Datenbank herzustellen. Wenn Sie eine Abfrage ausführen müssen, wählen Sie eine einfache SELECT-Abfrage aus, wie z.B. SELECT 1.

Fügen Sie einen Paketverweis auf AspNetCore.HealthChecks.SqlServer hinzu.

Geben Sie in der appsettings.json -Datei der App eine gültige Zeichenfolge für die Datenbankverbindung an. Die App verwendet eine SQL Server-Datenbank namens 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": "*"
}

Registrieren Sie Integritätsprüfungsdienste mit AddHealthChecks in Startup.ConfigureServices. Die Beispiel-App ruft die AddSqlServer-Methode mit der Verbindungszeichenfolge der Datenbank (DbHealthStartup.cs) auf:

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

Ein Integritätsprüfungs-Endpunkt wird durch Aufrufen von MapHealthChecks in Startup.Configure erstellt:

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

Um das Szenario für den Datenbanktest mithilfe der Beispiel-App auszuführen, verwenden Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell:

dotnet run --scenario db

Hinweis

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Entity Framework Core-DbContext-Test

Die DbContext-Überprüfung bestätigt, dass die App mit der Datenbank kommunizieren kann, die für einen EF Core-DbContext konfiguriert wurde. Die DbContext Überprüfung wird in Apps unterstützt, für die gilt:

AddDbContextCheck<TContext> registriert eine Integritätsprüfung für einen DbContext. Der DbContext wird als der TContext für die Methode bereitgestellt. Eine Überladung ist verfügbar, um den Fehlerstatus, Tags sowie eine benutzerdefinierte Testabfrage zu konfigurieren.

Standardmäßig:

  • Der DbContextHealthCheck ruft die CanConnectAsync-Methode von EF Core auf. Sie können festlegen, welcher Vorgang ausgeführt wird, wenn die Integrität mit AddDbContextCheck-Methodenüberladungen überprüft wird.
  • Der Name der Integritätsprüfung ist der Name des TContext-Typs.

In der Beispiel-App wird AppDbContext für AddDbContextCheck bereitgestellt und als Dienst in Startup.ConfigureServices (DbContextHealthStartup.cs) registriert:

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

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

Ein Integritätsprüfungs-Endpunkt wird durch Aufrufen von MapHealthChecks in Startup.Configure erstellt:

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

Stellen Sie sicher, dass die mit der Verbindungszeichenfolge angegebene Datenbank in der SQL Server-Instanz nicht vorhanden ist, um das DbContext-Testszenario mithilfe der Beispiel-App ausführen zu können. Falls die Datenbank vorhanden ist, löschen Sie sie.

Führen Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell aus:

dotnet run --scenario dbcontext

Wenn die App ausgeführt wird, überprüfen Sie den Integritätsstatus, indem Sie in einem Browser eine Anforderung an den /health-Endpunkt senden. Datenbank und AppDbContext sind nicht vorhanden, also sendet die App die folgende Antwort:

Unhealthy

Fordern Sie die Beispiel-App auf, die Datenbank zu erstellen. Senden Sie eine /createdatabase-Anforderung. Die App sendet die folgende Antwort:

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

Senden Sie eine Anforderung an den /health-Endpunkt. Datenbank und Kontext sind vorhanden, also sendet die App die folgende Antwort:

Healthy

Fordern Sie die Beispiel-App auf, die Datenbank zu löschen. Senden Sie eine /deletedatabase-Anforderung. Die App sendet die folgende Antwort:

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

Senden Sie eine Anforderung an den /health-Endpunkt. Die App meldet einen fehlerhaften Status:

Unhealthy

Separate Tests für Bereitschaft und Lebendigkeit

In einigen Hostingszenarien wird ein Integritätsprüfungspaar verwendet, mit dem zwischen zwei App-Status unterschieden wird:

  • Bereitschaft gibt an, ob die App ordnungsgemäß ausgeführt wird, aber nicht für den Empfang von Anforderungen bereit ist.
  • Livetest gibt an, ob eine App abgestürzt ist und neu gestartet werden muss.

Betrachten Sie das folgende Beispiel: Eine App muss eine große Konfigurationsdatei herunterladen, bevor sie für die Verarbeitung von Anforderungen bereit ist. Wir möchten nicht, dass die App neu gestartet wird, wenn der erste Download fehlschlägt, da die App mehrmals versuchen kann, die Datei herunterzuladen. Wir verwenden einen Livetest, um den Livezustand des Prozesses zu beschreiben. Weitere Überprüfungen erfolgen nicht. Außerdem soll verhindert werden, dass Anforderungen an die App gesendet werden, bevor die Konfigurationsdatei erfolgreich heruntergeladen wurde. Wir verwenden einen Bereitschaftstest, um den Status "nicht bereit" anzugeben, bis der Download erfolgreich durchgeführt wurde und die App für den Empfang von Anforderungen bereit ist.

Die Beispiel-App enthält eine Integritätsprüfung, um den Abschluss eines Starttasks mit langer Ausführungsdauer in einem gehosteten Dienst zu melden. StartupHostedServiceHealthCheck macht die Eigenschaft StartupTaskCompleted verfügbar, die der gehostete Dienst auf true festlegen kann, wenn der Task mit langer Ausführungsdauer abgeschlossen ist (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."));
    }
}

Der Hintergrundtask mit langer Ausführungsdauer wird von einem gehosteten Dienst (Services/StartupHostedService) gestartet. Nach Abschluss des Tasks wird StartupHostedServiceHealthCheck.StartupTaskCompleted auf true festgelegt:

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()
    {
    }
}

Die Integritätsprüfung wird mit AddCheck zusammen mit dem gehosteten Dienst in Startup.ConfigureServices registriert. Da der gehostete Dienst die Eigenschaft in der Integritätsprüfung festlegen muss, wird die Integritätsprüfung ebenfalls im Dienstcontainer (LivenessProbeStartup.cs) registriert:

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>();

Ein Integritätsprüfungs-Endpunkt wird durch Aufrufen von MapHealthChecks in Startup.Configure erstellt. In der Beispiel-App wird der Integritätsprüfungs-Endpunkt erstellt unter:

  • /health/ready für die Bereitschaftsprüfung. Die Bereitschaftsprüfung filtert auf Integritätsprüfungen mit dem ready-Tag.
  • /health/live für die Lebendigkeitsprüfung. Die Lebendigkeitsprüfung filtert StartupHostedServiceHealthCheck durch Rückgabe von false in HealthCheckOptions.Predicate heraus (weitere Informationen unter Filtern von Integritätsprüfungen).

Im folgenden Beispielcode gilt Folgendes:

  • Die Bereitschaftsprüfung verwendet alle registrierten Überprüfungen mit dem Tag „Bereit“.
  • Predicate schließt alle Überprüfungen aus und gibt 200-OK zurück.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

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

Um das Szenario für die Konfiguration von Bereitschafts-/Lebendigkeitsprüfungen mithilfe der Beispiel-App auszuführen, verwenden Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell:

dotnet run --scenario liveness

Besuchen Sie /health/ready mehrmals in einem Browser, bis 15 Sekunden verstrichen sind. Die Integritätsprüfung meldet während der ersten 15 Sekunden Unhealthy. Nach 15 Sekunden meldet der Endpunkt Healthy, was darauf hindeutet, dass die Ausführung des Tasks mit langer Ausführungsdauer durch den gehosteten Dienst abgeschlossen wurde.

In diesem Beispiel wird auch ein Integritätsprüfungsherausgeber erstellt (IHealthCheckPublisher-Implementierung), der die erste Bereitschaftsprüfung mit einer Verzögerung von zwei Sekunden ausführt. Weitere Informationen finden Sie im Abschnitt Herausgeber der Integritätsprüfung.

Kubernetes-Beispiel

Die Verwendung von Bereitschafts- und Lebendigkeitstests ist in Umgebungen wie Kubernetes sehr nützlich. In Kubernetes muss eine App möglicherweise zeitaufwendige Startaufgaben ausführen, bevor sie Anforderungen wie z. B. das Testen der Verfügbarkeit der zugrunde liegenden Datenbank erfüllt. Durch Verwendung separater Überprüfungen kann der Orchestrator unterscheiden, ob eine App funktioniert, aber noch nicht bereit ist, oder ob die App nicht gestartet wurde. Weitere Informationen zu Bereitschafts- und Lebendigkeitstests in Kubernetes finden Sie in der Kubernetes-Dokumentation unter Configure Liveness and Readiness Probes (Konfigurieren von Lebendigkeits- und Bereitschaftstests).

Das folgende Beispiel veranschaulicht die Konfiguration eines Bereitschaftstests in 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

Metrikbasierter Test mit einem benutzerdefinierten Antwortwriter

Die Beispiel-App veranschaulicht eine Arbeitsspeicher-Integritätsprüfung mit einem benutzerdefinierten Antwortwriter.

MemoryHealthCheck meldet einen beeinträchtigten Status, wenn die App mehr Arbeitsspeicher verwendet, als für den Schwellenwert festgelegt wurde (1 GB in der Beispiel-App). Das HealthCheckResult enthält Garbage Collector-Informationen (GC) für die 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));
    }
}

Registrieren Sie Integritätsprüfungsdienste mit AddHealthChecks in Startup.ConfigureServices. Die Integritätsprüfung wird nicht durch Übergabe an AddCheck aktiviert, stattdessen wird MemoryHealthCheck als Dienst registriert. Alle bei IHealthCheck registrierten Dienste stehen für die Dienste und Middleware für Integritätsprüfungen zur Verfügung. Es wird empfohlen, Integritätsprüfungsdienste als Singleton-Dienste zu registrieren.

In CustomWriterStartup.cs der Beispiel-App:

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

Ein Integritätsprüfungs-Endpunkt wird durch Aufrufen von MapHealthChecks in Startup.Configure erstellt. Ein WriteResponse-Delegat wird in der ResponseWriter-Eigenschaft angegeben, um eine benutzerdefinierte JSON-Antwort auszugeben, wenn die Integritätsprüfung ausgeführt wird:

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

Der WriteResponse-Delegat formatiert das CompositeHealthCheckResult als JSON-Objekt und führt zu folgender JSON-Ausgabe für die Integritätsprüfungsantwort. Weitere Informationen finden Sie im Abschnitt Anpassen der Ausgabe.

Um den metrikbasierten Test mit benutzerdefinierter Ausgabe des Antwortwriters mithilfe der Beispiel-App auszuführen, verwenden Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell:

dotnet run --scenario writer

Hinweis

AspNetCore.Diagnostics.HealthChecks enthält Szenarios für metrikbasierte Integritätsprüfungen, einschließlich Prüfungen des Datenträgerspeichers und Lebendigkeitsprüfungen mit Maximalwert.

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Filtern nach Port

Rufen Sie RequireHost auf MapHealthChecks mit einem URL-Muster auf, das einen Port angibt, um die an diesen Port gerichteten Integritätsprüfungsanforderungen einzuschränken. Dieser Ansatz wird normalerweise in einer Containerumgebung verfolgt, um einen Port für Überwachungsdienste verfügbar zu machen.

Die Beispiel-App konfiguriert den Port mithilfe des Umgebungsvariablen-Konfigurationsanbieters. Der Port wird in der Datei launchSettings.json festgelegt und über eine Umgebungsvariable an den Konfigurationsanbieter übergeben. Sie müssen den Server auch so konfigurieren, dass er am Verwaltungsport auf Anforderungen lauscht.

Um die Beispiel-App zum Veranschaulichen der Konfiguration des Verwaltungsports zu verwenden, erstellen Sie die Datei launchSettings.json in einem Properties-Ordner.

Die folgende Properties/launchSettings.json-Datei in der Beispiel-App ist in den Projektdateien der Beispiel-App nicht vorhanden und muss manuell erstellt werden:

{
  "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/"
    }
  }
}

Registrieren Sie Integritätsprüfungsdienste mit AddHealthChecks in Startup.ConfigureServices. Erstellen Sie einen Integritätsprüfungs-Endpunkt durch Aufrufen von MapHealthChecks in Startup.Configure.

In der Beispiel-App gibt ein Aufruf von RequireHost auf dem Endpunkt in Startup.Configure den Verwaltungsport aus der Konfiguration an:

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

Endpunkte werden in der Beispiel-App in Startup.Configure erstellt. Im folgenden Beispielcode gilt Folgendes:

  • Die Bereitschaftsprüfung verwendet alle registrierten Überprüfungen mit dem Tag „Bereit“.
  • Predicate schließt alle Überprüfungen aus und gibt 200-OK zurück.
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

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

Hinweis

Sie können vermeiden, die Datei launchSettings.json in der Beispiel-App erstellen zu müssen, indem Sie den Verwaltungsport explizit im Code festlegen. Fügen Sie in Program.cs an der Stelle, an der HostBuilder erstellt wird, einen Aufruf von ListenAnyIP hinzu, und geben Sie den Endpunkt des Verwaltungsports der App an. Geben Sie in Configure von ManagementPortStartup.cs den Verwaltungsport mit RequireHost an:

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");
});

Um das Szenario für die Konfiguration des Verwaltungsports mithilfe der Beispiel-App auszuführen, verwenden Sie den folgenden Befehl aus dem Ordner des Projekts in einer Befehlsshell:

dotnet run --scenario port

Verteilen einer Integritätsprüfungsbibliothek

So verteilen Sie eine Integritätsprüfung als Bibliothek:

  1. Schreiben Sie eine Integritätsprüfung, die die IHealthCheck-Schnittstelle als eigenständige Klasse implementiert. Die Klasse kann Abhängigkeitsinjektion (Dependency Injection, DI), Typaktivierung und benannte Optionen verwenden, um auf Konfigurationsdaten zuzugreifen.

    In der Integritätsprüfungslogik von CheckHealthAsync gilt Folgendes:

    • data1 und data2 werden in der Methode verwendet, um die Integritätsprüfungslogik des Tests auszuführen.
    • AccessViolationException wird verarbeitet.

    Wenn eine AccessViolationException auftritt, wird der FailureStatus mit dem HealthCheckResult zurückgegeben, damit Benutzer den Integritätsprüfungs-Fehlerstatus konfigurieren können.

    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. Schreiben Sie eine Erweiterungsmethode mit Parametern, die von der nutzenden App in ihrer Startup.Configure-Methode aufgerufen werden. Nehmen Sie im folgenden Beispiel die folgende Signatur für die Integritätsprüfungsmethode an:

    ExampleHealthCheck(string, string, int )
    

    Die oben stehende Signatur gibt an, dass ExampleHealthCheck weitere Daten benötigt, um die Testlogik für die Integritätsprüfung zu verarbeiten. Die Daten werden für den Delegaten bereitgestellt, der zum Erstellen der Integritätsprüfungsinstanz verwendet wird, wenn die Integritätsprüfung bei einer Erweiterungsmethode registriert wird. Im folgenden Beispiel gibt der Aufrufer optional Folgendes an:

    • Name der Integritätsprüfung (name). Wenn der Wert null ist, wird example_health_check verwendet.
    • string-Datenpunkt für die Integritätsprüfung (data1).
    • integer-Datenpunkt für die Integritätsprüfung (data2). Wenn der Wert null ist, wird 1 verwendet.
    • Fehlerstatus (HealthStatus). Der Standardwert ist null. Wenn der Wert null ist, wird HealthStatus.Unhealthy für einen Fehlerstatus gemeldet.
    • Tags (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));
        }
    }
    

Herausgeber der Integritätsprüfung

Wenn dem Dienstcontainer ein IHealthCheckPublisher hinzugefügt wird, führt das Integritätsprüfungssystem Ihre Integritätsprüfungen regelmäßig aus und ruft PublishAsync mit dem Ergebnis auf. Dies ist nützlich in einem Szenario mit pushbasiertem Integritätsüberwachungssystem, in dem jeder Prozess das Überwachungssystem regelmäßig aufrufen muss, um die Integrität zu bestimmen.

Die IHealthCheckPublisher-Schnittstelle weist eine einzige Methode auf:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions ermöglichen Ihnen, Folgendes festzulegen:

  • Delay: Hierbei handelt es sich um die angewendete anfängliche Verzögerung zwischen dem Start der App und der Ausführung von IHealthCheckPublisher-Instanzen. Die Verzögerung wird einmal beim Start angewendet und gilt nicht für die nachfolgenden Iterationen. Der Standardwert beträgt fünf Sekunden.
  • Period: Hierbei handelt es sich um die Dauer der Ausführung von IHealthCheckPublisher. Der Standardwert ist 30 Sekunden.
  • Predicate: Wenn der Wert für Predicatenull ist (Standard), führt der Veröffentlichungsdienst für die Integritätsprüfung alle registrierten Integritätsprüfungen durch. Um eine Teilmenge von Integritätsprüfungen auszuführen, stellen Sie eine Funktion bereit, die die Menge der Prüfungen filtert. Das Prädikat wird in jedem Zeitraum ausgewertet.
  • Timeout: Hierbei handelt es sich um das Zeitlimit für die Ausführung der Integritätsprüfungen für alle IHealthCheckPublisher-Instanzen. Verwenden Sie InfiniteTimeSpan zur Ausführung ohne Timeout. Der Standardwert ist 30 Sekunden.

In der Beispiel-App ist ReadinessPublisher eine IHealthCheckPublisher-Implementierung. Der Integritätsprüfungsstatus wird für jede Überprüfung auf folgenden Protokollebenen protokolliert:

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;
    }
}

Im Beispiel LivenessProbeStartup der Beispiel-App StartupHostedService hat die Bereitschaftsprüfung eine Startverzögerung von zwei Sekunden und führt die Prüfung alle 30 Sekunden aus. Zum Aktivieren der IHealthCheckPublisher Implementierung registriert das Beispiel ReadinessPublisher als Singletondienst im Abhängigkeitsinjektionscontainer (Dependency Injection, DI):

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>();

Hinweis

AspNetCore.Diagnostics.HealthChecks enthält Herausgeber für verschiedene Systeme, einschließlich Application Insights.

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Einschränken von Integritätsprüfungen mit MapWhen

Verwenden Sie MapWhen, um die Anforderungspipeline für Endpunkte von Integritätsprüfungen bedingt zu branchen.

Im folgenden Beispiel verzweigt MapWhen die Anforderungspipeline so, dass die Middleware für Integritätsprüfungen aktiviert wird, wenn eine GET-Anforderung für den Endpunkt api/HealthCheck empfangen wird:

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

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

Weitere Informationen finden Sie unter ASP.NET Core-Middleware.

ASP.NET Core bietet Middleware für Integritätsprüfungen und Bibliotheken für die Berichterstellung für Komponenten der App-Infrastruktur.

Integritätsprüfungen werden von einer App als HTTP-Endpunkte verfügbar gemacht. Endpunkte für die Integritätsprüfung können für verschiedene Echtzeitüberwachungsszenarien konfiguriert werden:

  • Integritätstests können von Containerorchestratoren und Lastenausgleichsmodulen verwendet werden, um den Status einer App zu überprüfen. Ein Containerorchestrator kann z.B. auf eine fehlerhafte Integritätsprüfung reagieren, indem die Ausführung einer Bereitstellung angehalten oder ein Container neu gestartet wird. Ein Lastenausgleichsmodul kann auf eine fehlerhafte App reagieren, indem Datenverkehr von der fehlerhaften zu einer fehlerfreien Instanz umgeleitet wird.
  • Die Nutzung von Arbeitsspeicher, Datenträgern und anderen physischen Serverressourcen kann auf einen fehlerfreien Status überwacht werden.
  • Integritätsprüfungen können die Abhängigkeiten einer App testen, wie z.B. Datenbanken und externe Dienstendpunkte, um Verfügbarkeit und normale Funktionsweise zu bestätigen.

Integritätsprüfungen werden in der Regel mit einem externen Überwachungsdienst oder Containerorchestrator verwendet, um den Status einer App zu überprüfen. Bevor Sie Integritätsprüfungen zu einer App hinzufügen, entscheiden Sie, welches Überwachungssystem verwendet werden soll. Das Überwachungssystem bestimmt, welche Arten von Integritätsprüfungen erstellt und wie die jeweiligen Endpunkte konfiguriert werden müssen.

Grundlegender Integritätstest

In vielen Apps genügt zur Ermittlung des App-Status eine grundlegende Integritätstestkonfiguration, die die Verfügbarkeit der App für die Verarbeitung von Anforderungen (Lebendigkeit) meldet.

Die grundlegende Konfiguration registriert Integritätsprüfungsdienste und ruft die Middleware für Integritätsprüfungen auf, damit diese an einem URL-Endpunkt mit dem Integritätsstatus antwortet. Standardmäßig werden keine spezifischen Integritätsprüfungen registriert, um eine bestimmte Abhängigkeit oder ein bestimmtes Subsystem zu testen. Die App wird als fehlerfrei angesehen, wenn sie an der URL des Integritätsendpunkts antworten kann. Der Standardantwortwriter schreibt HealthStatus als Klartextantwort an den Client. HealthStatus ist HealthStatus.Healthy, HealthStatus.Degraded oder HealthStatus.Unhealthy.

Registrieren Sie Integritätsprüfungsdienste mit AddHealthChecks in Program.cs. Erstellen Sie einen Integritätsprüfungsendpunkt durch Aufrufen von MapHealthChecks.

Im folgenden Beispiel wird ein Integritätsprüfungsendpunkt unter /healthz erstellt:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker HEALTHCHECK

Docker bietet eine integrierte HEALTHCHECK-Direktive, mit der Sie den Status einer App überprüfen können, die die grundlegende Konfiguration für Integritätsprüfungen verwendet:

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

Das vorherige Beispiel verwendet curl, um eine HTTP-Anforderung an den Integritätsprüfungsendpunkt bei /healthz auszugeben. curl ist nicht in den .NET Linux-Containerimages enthalten, kann aber hinzugefügt werden, indem das erforderliche Paket in der Dockerfile installiert wird. Container, die auf Alpine Linux basierende Images verwenden, können das enthaltene wget anstelle von curl verwenden.

Erstellen von Integritätsprüfungen

Integritätsprüfungen werden durch Implementieren der IHealthCheck-Schnittstelle erstellt. Die CheckHealthAsync-Methode gibt ein HealthCheckResult zurück, das die Integrität als Healthy, Degraded oder Unhealthy angibt. Das Ergebnis wird als Klartextantwort mit einem konfigurierbaren Statuscode geschrieben. Die Konfiguration wird im Abschnitt Integritätsprüfungsoptionen beschrieben. HealthCheckResult kann auch optionale Schlüssel-Wert-Paare zurückgeben.

Das folgende Beispiel veranschaulicht das Layout einer Integritätsprüfung:

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."));
    }
}

Die Integritätsprüfungslogik wird in der CheckHealthAsync-Methode platziert. Im vorherigen Beispiel wird die Dummyvariable isHealthy auf true festgelegt. Wenn der Wert von isHealthy auf false festgelegt ist, wird der HealthCheckRegistration.FailureStatus-Status zurückgegeben.

Wenn CheckHealthAsync während der Überprüfung eine Ausnahme auslöst, wird ein neues Element HealthReportEntry zurückgegeben, dessen HealthReportEntry.Status auf FailureStatus festgelegt ist. Dieser Status ist definiert durch AddCheck (weitere Informationen finden Sie im Abschnitt Registrieren von Diensten zur Integritätsprüfung) und enthält die innere Ausnahme, die den Prüfungsfehler verursacht hat. Description ist auf die Meldung der Ausnahme festgelegt.

Registrieren von Integritätsprüfungsdiensten

Rufen Sie AddCheck in Program.cs auf, um einen Integritätsprüfungsdienst zu registrieren:

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

Die in der folgenden Abbildung gezeigte AddCheck-Überladung legt den Fehlerstatus (HealthStatus) fest, der angegeben werden soll, wenn die Integritätsprüfung einen Fehler meldet. Wenn der Fehlerstatus auf null (Standardwert) festgelegt ist, wird HealthStatus.Unhealthy gemeldet. Diese Überladung ist ein nützliches Szenario für Bibliotheksersteller: Bei einem Integritätsprüfungsfehler wird der durch die Bibliothek angegebene Fehlerstatus von der App erzwungen, wenn die Implementierung der Integritätsprüfung die Einstellung berücksichtigt.

Tags können zum Filtern von Integritätsprüfungen verwendet werden. Tags werden im Abschnitt Filtern von Integritätsprüfungen beschrieben.

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

AddCheck kann auch eine Lambdafunktion ausführen. Im folgenden Beispiel gibt die Integritätsprüfung immer ein fehlerfreies Ergebnis zurück:

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

Rufen Sie AddTypeActivatedCheck auf, um Argumente an die Implementierung einer Integritätsprüfung zu übergeben. Im folgenden Beispiel akzeptiert eine typaktivierte Integritätsprüfung in ihrem Konstruktor eine ganze Zahl und eine Zeichenfolge:

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."));
    }
}

Um die vorherige Integritätsprüfung zu registrieren, rufen Sie AddTypeActivatedCheck mit der ganzen Zahl und der Zeichenfolge auf, die als Argumente übergeben werden:

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

Verwenden von Integritätsprüfungsrouting

Rufen Sie in Program.cs auf der Endpunkterstellung mit der Endpunkt-URL oder dem relativen Pfad MapHealthChecks auf:

app.MapHealthChecks("/healthz");

Anfordern des Hosts

Rufen Sie RequireHost auf, um einen oder mehrere zugelassene Hosts für den Integritätsprüfungs-Endpunkt anzugeben. Hosts sollten Unicode anstelle von Punycode verwenden und können einen Port enthalten. Wenn keine Sammlung bereitgestellt wird, wird jeder Host akzeptiert:

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

Um den Integritätsprüfungsendpunkt so einzuschränken, dass er nur an einem bestimmten Port antwortet, geben Sie beim Aufruf von RequireHost einen Port an. Dieser Ansatz wird normalerweise in einer Containerumgebung verfolgt, um einen Port für Überwachungsdienste verfügbar zu machen:

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

Warnung

Die APIs, die auf dem Hostheader basieren, z. B. HttpRequest.Host und RequireHost, sind potenziellem Spoofing durch Clients ausgesetzt.

Verwenden Sie einen der folgenden Ansätze, um Host- und Portspoofing zu verhindern:

Um zu verhindern, dass nicht autorisierte Clients den Port spoofen, rufen Sie RequireAuthorization auf:

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

Weitere Informationen finden Sie unter Hostabgleich in Routen mit RequireHost.

Anfordern der Autorisierung

Rufen Sie RequireAuthorization auf, um die Autorisierungsmiddleware auf dem Integritätsprüfungs-Anforderungsendpunkt auszuführen. Eine RequireAuthorization-Überladung akzeptiert eine oder mehrere Autorisierungsrichtlinien. Wenn keine Richtlinie bereitgestellt wird, wird die standardmäßige Autorisierungsrichtlinie verwendet:

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

Aktivieren ursprungsübergreifender Anforderungen (CORS)

Obwohl das manuelle Ausführen von Integritätsprüfungen über einen Browser kein gängiges Szenario ist, kann CORS-Middleware durch Aufrufen von RequireCors für Integritätsprüfungsendpunkte aktiviert werden. Eine RequireCors-Überladung akzeptiert einen CORS-Richtliniengenerator-Delegaten (CorsPolicyBuilder) oder einen Richtliniennamen. Weitere Informationen finden Sie unter Aktivieren ursprungsübergreifender Anforderungen (Cross-Origin Requests, CORS) in ASP.NET Core.

Optionen für die Integritätsprüfung

HealthCheckOptions ermöglichen die Anpassung des Verhaltens von Integritätsprüfungen:

Filtern von Integritätsprüfungen

Standardmäßig führt die Middleware für Integritätsprüfungen alle registrierten Integritätsprüfungen aus. Um eine Teilmenge von Integritätsprüfungen auszuführen, stellen Sie eine Funktion bereit, die einen booleschen Wert an die Option Predicate zurückgibt.

Im folgenden Beispiel werden die Integritätsprüfungen so gefiltert, dass nur die mit sample gekennzeichneten ausgeführt werden:

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

Anpassen des HTTP-Statuscodes

Verwenden Sie ResultStatusCodes, um die Zuordnung des Integritätsstatus zu HTTP-Statuscodes anzupassen. Die folgenden StatusCodes-Zuweisungen stellen die von der Middleware verwendeten Standardwerte dar. Ändern Sie die Statuscodewerte so, dass sie Ihren Anforderungen entsprechen:

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

Unterdrücken von Cacheheadern

AllowCachingResponses steuert, ob die Middleware für Integritätsprüfungen einer Testantwort HTTP-Header hinzufügt, um das Zwischenspeichern von Antworten zu verhindern. Wenn der Wert false (Standard) lautet, legt die Middleware die Header Cache-Control, Expires und Pragma fest oder überschreibt sie, um eine Zwischenspeicherung der Antworten zu verhindern. Wenn der Wert true lautet, ändert die Middleware die Cacheheader der Antwort nicht:

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

Anpassen der Ausgabe

Um die Ausgabe eines Integritätsprüfungsberichts anzupassen, legen Sie die Eigenschaft HealthCheckOptions.ResponseWriter für einen Delegaten fest, der die Antwort schreibt:

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

Der Standarddelegat schreibt eine minimale Klartextantwort mit dem Zeichenfolgenwert HealthReport.Status. Der folgende benutzerdefinierte Delegat gibt eine benutzerdefinierte JSON-Antwort mithilfe von System.Text.Json aus:

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()));
}

Die Integritätsprüfungs-API bietet keine integrierte Unterstützung für komplexe JSON-Rückgabeformate, da das Format für Ihre Überwachungssystemauswahl spezifisch ist. Passen Sie die Antwort in den vorangehenden Beispielen nach Bedarf an. Weitere Informationen zur JSON-Serialisierung mit System.Text.Json finden Sie unter Serialisieren und Deserialisieren von JSON in .NET.

Datenbanktest

Eine Integritätsprüfung kann eine Datenbankabfrage angeben, die als boolescher Test ausgeführt wird, um zu ermitteln, ob die Datenbank normal reagiert.

AspNetCore.Diagnostics.HealthChecks, eine Integritätsprüfungsbibliothek für ASP.NET Core-Apps, enthält eine Integritätsprüfung, die für eine SQL Server-Datenbank ausgeführt wird. AspNetCore.Diagnostics.HealthChecks führt eine SELECT 1-Abfrage in der Datenbank aus, um zu bestätigen, dass die Verbindung mit der Datenbank fehlerfrei ist.

Warnung

Wenn Sie die Datenbankverbindung mithilfe einer Abfrage überprüfen, wählen Sie eine Abfrage aus, die eine schnelle Antwort zurückgibt. Bei einer Abfrage besteht immer das Risiko, dass die Datenbank überladen und ihre Leistung beeinträchtigt wird. In den meisten Fällen ist es nicht notwendig, eine Testabfrage auszuführen. Es genügt zumeist, einfach erfolgreich eine Verbindung mit der Datenbank herzustellen. Wenn Sie eine Abfrage ausführen müssen, wählen Sie eine einfache SELECT-Abfrage aus, wie z.B. SELECT 1.

Um diese SQL Server-Integritätsprüfung zu verwenden, fügen Sie einen Paketverweis auf das NuGet-Paket AspNetCore.HealthChecks.SqlServer ein. Im folgenden Beispiel wird die SQL Server-Integritätsüberprüfung registriert:

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

Hinweis

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Entity Framework Core-DbContext-Test

Die DbContext-Überprüfung bestätigt, dass die App mit der Datenbank kommunizieren kann, die für einen EF Core-DbContext konfiguriert wurde. Die DbContext Überprüfung wird in Apps unterstützt, für die gilt:

AddDbContextCheck registriert eine Integritätsprüfung für einen DbContext. DbContext wird der Methode als TContext bereitgestellt. Eine Überladung ist verfügbar, um den Fehlerstatus, Tags sowie eine benutzerdefinierte Testabfrage zu konfigurieren.

Standardmäßig:

  • Der DbContextHealthCheck ruft die CanConnectAsync-Methode von EF Core auf. Sie können festlegen, welcher Vorgang ausgeführt wird, wenn die Integrität mit AddDbContextCheck-Methodenüberladungen überprüft wird.
  • Der Name der Integritätsprüfung ist der Name des TContext-Typs.

Im folgenden Beispiel werden ein DbContext und ein zugeordneter DbContextHealthCheck registriert:

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

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

Separate Tests für Bereitschaft und Lebendigkeit

In einigen Hostingszenarien wird ein Integritätsprüfungspaar verwendet, mit dem zwischen zwei App-Status unterschieden wird:

  • Bereitschaft gibt an, ob die App ordnungsgemäß ausgeführt wird, aber nicht für den Empfang von Anforderungen bereit ist.
  • Livetest gibt an, ob eine App abgestürzt ist und neu gestartet werden muss.

Betrachten Sie das folgende Beispiel: Eine App muss eine große Konfigurationsdatei herunterladen, bevor sie für die Verarbeitung von Anforderungen bereit ist. Wir möchten nicht, dass die App neu gestartet wird, wenn der erste Download fehlschlägt, da die App mehrmals versuchen kann, die Datei herunterzuladen. Wir verwenden einen Livetest, um den Livezustand des Prozesses zu beschreiben. Weitere Überprüfungen erfolgen nicht. Außerdem soll verhindert werden, dass Anforderungen an die App gesendet werden, bevor die Konfigurationsdatei erfolgreich heruntergeladen wurde. Wir verwenden einen Bereitschaftstest, um den Status "nicht bereit" anzugeben, bis der Download erfolgreich durchgeführt wurde und die App für den Empfang von Anforderungen bereit ist.

Die folgende Hintergrundaufgabe simuliert einen Startprozess, der ungefähr 15 Sekunden dauert. Nach Abschluss des Vorgangs legt die Aufgabe die StartupHealthCheck.StartupCompleted-Eigenschaft auf TRUE fest:

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;
    }
}

StartupHealthCheck meldet die Beendigung der lang ausgeführten Startaufgabe und macht die Eigenschaft StartupCompleted verfügbar, die vom Hintergrunddienst festgelegt wird:

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."));
    }
}

Die Integritätsprüfung wird mit AddCheck zusammen mit dem gehosteten Dienst in Program.cs registriert. Da der gehostete Dienst die Eigenschaft in der Integritätsprüfung festlegen muss, wird die Integritätsprüfung ebenfalls im Dienstcontainer als Singleton registriert:

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

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

Um zwei verschiedene Integritätsprüfungsendpunkte zu erstellen, rufen Sie MapHealthChecks zweimal auf:

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

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

Im vorherigen Beispiel werden die folgenden Integritätsprüfungsendpunkte erstellt:

  • /healthz/ready für die Bereitschaftsprüfung. Die Bereitschaftsprüfung filtert Integritätsprüfungen heraus, die mit ready gekennzeichnet sind.
  • /healthz/live für die Lebendigkeitsprüfung. Die Liveüberprüfung filtert alle Integritätsprüfungen heraus, indem false im Delegaten HealthCheckOptions.Predicate zurückgegeben wird. Weitere Informationen zum Filtern von Integritätsprüfungen finden Sie unter Filtern von Integritätsprüfungen in diesem Artikel.

Bevor die Startaufgabe abgeschlossen ist, meldet der Endpunkt /healthz/ready den Status Unhealthy. Bevor die Startaufgabe abgeschlossen ist, meldet dieser Endpunkt den Status Healthy. Der Endpunkt /healthz/live schließt alle Überprüfungen aus und meldet für alle Aufrufe den Status Healthy.

Kubernetes-Beispiel

Die Verwendung von Bereitschafts- und Lebendigkeitstests ist in Umgebungen wie Kubernetes sehr nützlich. In Kubernetes muss eine App möglicherweise zeitaufwendige Startaufgaben ausführen, bevor sie Anforderungen wie z. B. das Testen der Verfügbarkeit der zugrunde liegenden Datenbank erfüllt. Durch Verwendung separater Überprüfungen kann der Orchestrator unterscheiden, ob eine App funktioniert, aber noch nicht bereit ist, oder ob die App nicht gestartet wurde. Weitere Informationen zu Bereitschafts- und Lebendigkeitstests in Kubernetes finden Sie in der Kubernetes-Dokumentation unter Configure Liveness and Readiness Probes (Konfigurieren von Lebendigkeits- und Bereitschaftstests).

Das folgende Beispiel veranschaulicht die Konfiguration eines Bereitschaftstests in 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

Verteilen einer Integritätsprüfungsbibliothek

So verteilen Sie eine Integritätsprüfung als Bibliothek:

  1. Schreiben Sie eine Integritätsprüfung, die die IHealthCheck-Schnittstelle als eigenständige Klasse implementiert. Die Klasse kann Abhängigkeitsinjektion (Dependency Injection, DI), Typaktivierung und benannte Optionen verwenden, um auf Konfigurationsdaten zuzugreifen.

  2. Schreiben Sie eine Erweiterungsmethode mit Parametern, die von der nutzenden App in ihrer Program.cs-Methode aufgerufen werden. Betrachten Sie das folgende Beispiel einer Integritätsprüfung, die arg1 und arg2 als Konstruktorparameter akzeptiert:

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

    Die vorherige Signatur gibt an, dass die Integritätsprüfung benutzerdefinierte Daten benötigt, um die Prüflogik der Integritätsprüfung zu verarbeiten. Die Daten werden für den Delegaten bereitgestellt, der zum Erstellen der Integritätsprüfungsinstanz verwendet wird, wenn die Integritätsprüfung bei einer Erweiterungsmethode registriert wird. Im folgenden Beispiel gibt der Aufrufer Folgendes an:

    • arg1: ein integer-Datenpunkt für die Integritätsprüfung.
    • arg2: ein Zeichenfolgenargument für die Integritätsprüfung.
    • name: ein optionaler Name der Integritätsprüfung. Falls null, wird ein Standardwert verwendet.
    • failureStatus: ein optionales Element HealthStatus, das bei einem Fehlerstatus gemeldet wird. Wenn der Wert null ist, wird HealthStatus.Unhealthy verwendet.
    • tags: eine optionale IEnumerable<string>-Sammlung von Tags.
    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));
        }
    }
    

Herausgeber der Integritätsprüfung

Wenn dem Dienstcontainer ein IHealthCheckPublisher hinzugefügt wird, führt das Integritätsprüfungssystem Ihre Integritätsprüfungen regelmäßig aus und ruft PublishAsync mit dem Ergebnis auf. Dieser Prozess ist nützlich in einem Szenario mit pushbasiertem Integritätsüberwachungssystem, in dem jeder Prozess das Überwachungssystem regelmäßig aufrufen muss, um Integrität zu bestimmen.

HealthCheckPublisherOptions ermöglichen Ihnen, Folgendes festzulegen:

  • Delay: Hierbei handelt es sich um die angewendete anfängliche Verzögerung zwischen dem Start der App und der Ausführung von IHealthCheckPublisher-Instanzen. Die Verzögerung wird einmal beim Start angewendet und gilt nicht für spätere Iterationen. Der Standardwert beträgt fünf Sekunden.
  • Period: Hierbei handelt es sich um die Dauer der Ausführung von IHealthCheckPublisher. Der Standardwert ist 30 Sekunden.
  • Predicate: Wenn der Wert für Predicatenull ist (Standard), führt der Veröffentlichungsdienst für die Integritätsprüfung alle registrierten Integritätsprüfungen durch. Um eine Teilmenge von Integritätsprüfungen auszuführen, stellen Sie eine Funktion bereit, die die Menge der Prüfungen filtert. Das Prädikat wird in jedem Zeitraum ausgewertet.
  • Timeout: Hierbei handelt es sich um das Zeitlimit für die Ausführung der Integritätsprüfungen für alle IHealthCheckPublisher-Instanzen. Verwenden Sie InfiniteTimeSpan zur Ausführung ohne Timeout. Der Standardwert ist 30 Sekunden.

Das folgende Beispiel veranschaulicht das Layout eines Integritätsprüfungsherausgebers:

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

        return Task.CompletedTask;
    }
}

Die HealthCheckPublisherOptions-Klasse stellt Eigenschaften zum Konfigurieren des Verhaltens des Integritätsprüfungsherausgebers bereit.

Im folgenden Beispiel wird ein Integritätsprüfungsherausgeber als Singleton registriert und HealthCheckPublisherOptions konfiguriert:

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

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

Hinweis

AspNetCore.Diagnostics.HealthChecks enthält Herausgeber für verschiedene Systeme, einschließlich Application Insights.

AspNetCore.Diagnostics.HealthChecks wird nicht von Microsoft verwaltet oder unterstützt.

Abhängigkeitsinjektion und Integritätsprüfungen

Es ist möglich, eine Instanz eines bestimmten Type innerhalb einer Integritätsprüfungsklasse über eine Abhängigkeitsinjektion zu verwenden. Die Abhängigkeitsinjektion kann hilfreich sein, um Optionen oder eine globale Konfiguration in eine Integritätsprüfung einzufügen. Die Verwendung der Abhängigkeitsinjektion ist kein gängiges Szenario zum Konfigurieren von Integritätsprüfungen. In der Regel ist jede Integritätsprüfung spezifisch für den tatsächlichen Test und wird mithilfe von IHealthChecksBuilder-Erweiterungsmethoden konfiguriert.

Das folgende Beispiel zeigt ein Beispiel für eine Integritätsprüfung, die ein Konfigurationsobjekt über eine Abhängigkeitsinjektion abruft:

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."));
    }
}

SampleHealthCheckWithDiConfig und die Integritätsprüfung müssen dem Dienstcontainer hinzugefügt werden:

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 im Vergleich zu MapHealthChecks

Es gibt zwei Möglichkeiten, Integritätsprüfungen für Aufrufer zugänglich zu machen:

  • UseHealthChecks registriert Middleware für die Verarbeitung von Integritätsprüfungsanforderungen in der Middlewarepipeline.
  • MapHealthChecks registriert einen Integritätsprüfungsendpunkt. Der Endpunkt wird zusammen mit anderen Endpunkten in der App abgeglichen und ausgeführt.

Der Vorteil der Verwendung von MapHealthChecks gegenüber UseHealthChecks ist die Möglichkeit, endpunktfähige Middleware wie Autorisierung zu verwenden und eine präzisere Kontrolle über die Abgleichsrichtlinie zu haben. Der Hauptvorteil der Verwendung von UseHealthChecks gegenüber MapHealthChecks besteht darin, genau zu steuern, wo Integritätsprüfungen in der Middlewarepipeline ausgeführt werden.

UseHealthChecks:

  • Beendet die Pipeline, wenn eine Anforderung mit dem Integritätsprüfungsendpunkt übereinstimmt. Kurzschlüsse sind häufig wünschenswert, da dadurch unnötige Arbeit vermieden wird, z. B. Protokollierung und andere Middleware.
  • Wird in erster Linie zum Konfigurieren der Integritätsprüfungsmiddleware in der Pipeline verwendet.
  • Kann einen beliebigen Pfad an einem Port mit einem null-Wert oder einem leeren PathString-Wert abgleichen. Ermöglicht das Durchführen einer Integritätsprüfung für jede Anforderung, die an den angegebenen Port gestellt wird.
  • Quellcode

MapHealthChecks ermöglicht:

  • Zuordnen bestimmter Routen oder Endpunkte für Integritätsprüfungen.
  • Anpassen der URL oder des Pfads, unter der bzw. dem auf den Integritätsprüfungsendpunkt zugegriffen werden kann.
  • Zuordnen mehrerer Integritätsprüfungsendpunkte mit unterschiedlichen Routen oder Konfigurationen. Unterstützung mehrerer Endpunkte:
    • Aktiviert separate Endpunkte für verschiedene Arten von Integritätsprüfungen oder -komponenten.
    • Wird verwendet, um zwischen verschiedenen Aspekten der App-Integrität zu unterscheiden oder bestimmte Konfigurationen auf Teilmengen von Integritätsprüfungen anzuwenden.
  • Quellcode

Zusätzliche Ressourcen

Hinweis

Dieser Artikel wurde teilweise mit Hilfe künstlicher Intelligenz erstellt. Vor der Veröffentlichung hat ein Autor den Inhalt geprüft und nach Bedarf überarbeitet. Weitere Informationen finden Sie unter Unsere Prinzipien für die Verwendung von KI-generierten Inhalten in Microsoft Learn.