Behandeln von Fehlern in Minimal-API-Apps

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.

Warnung

Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der Supportrichtlinie für .NET und .NET Core. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Wichtig

Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.

Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.

Mit Beiträgen von David Acker

In diesem Artikel wird beschrieben, wie Sie Fehler in Minimal-API-Apps behandeln. Informationen zur Fehlerbehandlung in controllerbasierten APIs finden Sie unter Behandeln von Fehlern in ASP.NET Core und Behandeln von Fehlern in ASP.NET Core-controllerbasierten Web-APIs.

Ausnahmen

In einer Minimal-API-App gibt es zwei verschiedene integrierte und zentralisierte Verfahren zum Behandeln von Ausnahmefehlern:

In diesem Abschnitt wird auf die folgende Beispiel-App verwiesen, um Möglichkeiten zum Behandeln von Ausnahmen in einer Minimal-API zu veranschaulichen. Sie löst eine Ausnahme aus, wenn der Endpunkt /exception angefordert wird:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Seite mit Ausnahmen für Entwickler

Die Seite mit Ausnahmen für Entwickler enthält ausführliche Informationen zu unbehandelten Anforderungsausnahmen. Es verwendet DeveloperExceptionPageMiddleware, um synchrone und asynchrone Ausnahmen aus der HTTP-Pipeline zu erfassen und um Fehlerantworten zu generieren. Die Seite mit Ausnahmen für Entwickler wird früh in der Middlewarepipeline ausgeführt, sodass in der nachfolgenden Middleware ausgelöste unbehandelte Ausnahmen abgefangen werden.

ASP.NET Core-Apps aktivieren standardmäßig die Seite mit Ausnahmen für Entwickler, wenn die folgenden Aussagen beide zutreffen:

Apps, die mit früheren Vorlagen erstellt wurden, d. h. mithilfe von WebHost.CreateDefaultBuilder, können die Seite mit Ausnahmen für Entwickler durch Aufrufen von app.UseDeveloperExceptionPage aktivieren.

Warnung

Aktivieren Sie die Seite für Entwicklerausnahmen nur, wenn die App in der Entwicklungsumgebung ausgeführt wird. Wenn die App in der Produktionsumgebung ausgeführt wird, sollten Sie keine detaillierten Ausnahmeinformationen öffentlich teilen. Weitere Informationen zum Konfigurieren der Umgebung finden Sie unter Verwenden mehrerer Umgebungen in ASP.NET Core.

Die Seite mit Ausnahmen für Entwickler kann die folgenden Informationen zu der Ausnahme und der Anforderung enthalten:

  • Stapelüberwachung
  • Abfragezeichenfolgeparameter, sofern vorhanden
  • Cookies (sofern vorhanden)
  • Headers
  • Endpunktmetadaten (falls vorhanden)

Es ist nicht garantiert, dass auf der Seite mit Ausnahmen für Entwickler Informationen angezeigt werden. Vollständige Informationen zu Fehlern finden Sie unter Protokollierung.

Die folgende Abbildung zeigt eine Beispielseite für Entwicklerausnahmen mit Animation, um die Registerkarten und die angezeigten Informationen anzuzeigen:

Seite mit Ausnahmen für Entwickler animiert, um jede ausgewählte Registerkarte anzuzeigen.

Als Reaktion auf eine Anforderung mit einem Accept: text/plain-Header gibt die Seite mit Ausnahmen für Entwickler nur Text anstelle von HTML zurück. Zum Beispiel:

Status: 500 Internal Server Error
Time: 9.39 msSize: 480 bytes
FormattedRawHeadersRequest
Body
text/plain; charset=utf-8, 480 bytes
System.InvalidOperationException: Sample Exception
   at WebApplicationMinimal.Program.<>c.<Main>b__0_0() in C:\Source\WebApplicationMinimal\Program.cs:line 12
   at lambda_method1(Closure, Object, HttpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

HEADERS
=======
Accept: text/plain
Host: localhost:7267
traceparent: 00-0eab195ea19d07b90a46cd7d6bf2f

So gelangen Sie zur Seite mit Ausnahmen für Entwickler:

  • Führen Sie die Beispiel-App in der Entwicklungsumgebung aus.
  • Wechseln Sie zum /exception-Endpunkt.

Ausnahmehandler

In Nicht-Entwicklungsumgebungen kann Middleware zur Ausnahmebehandlung verwendet werden, um Fehlernutzdaten zu generieren. Rufen Sie UseExceptionHandler auf, um Exception Handler Middleware zu konfigurieren.

Der folgende Code ändert die App beispielsweise so, dass sie dem Client mit RFC 7807-konformen Nutzdaten antwortet. Weitere Informationen finden Sie im Abschnitt Problemdetails weiter unten in diesem Artikel.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp 
    => exceptionHandlerApp.Run(async context 
        => await Results.Problem()
                     .ExecuteAsync(context)));

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Client- und Serverfehlerantworten

Betrachten Sie die folgende Minimal-API-App.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Der /users-Endpunkt generiert 200 OK mit einer json-Darstellung von User, wenn id größer als 0 ist, und andernfalls den Statuscode 400 BAD REQUEST ohne Antworttext. Weitere Informationen zum Erstellen einer Antwort finden Sie unter Erstellen von Antworten in Minimal-API-Apps.

Status Code Pages middleware kann so konfiguriert werden, dass für alle HTTP-Antworten vom Client (400-499) oder Server (500 -599) ein allgemeiner Textinhalt erzeugt wird, wenn er leer ist. Die Middleware wird durch Aufrufen der UseStatusCodePages-Erweiterungsmethode konfiguriert.

Im folgenden Beispiel wird die App beispielsweise so geändert, dass sie dem Client mit RFC 7807-konformen Nutzdaten für alle Client- und Serverantworten reagiert, einschließlich Routingfehlern (z. B. 404 NOT FOUND). Weitere Informationen finden Sie im Abschnitt zu Problemdetails.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseStatusCodePages(async statusCodeContext 
    => await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
                 .ExecuteAsync(statusCodeContext.HttpContext));

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Problemdetails

Problemdetails sind nicht das einzige Antwortformat zur Beschreibung eines HTTP-API-Fehlers, sie werden jedoch häufig verwendet, um Fehler für HTTP-APIs zu melden.

Der Dienst für Problemdetails implementiert die IProblemDetailsService-Schnittstelle, die das Erstellen von Problemdetails in ASP.NET Core unterstützt. Die Erweiterungsmethode AddProblemDetails(IServiceCollection) in IServiceCollection registriert die Standardimplementierung von IProblemDetailsService.

In ASP.NET Core-Apps generiert die folgende Middleware HTTP-Antworten mit Problemdetails, wenn AddProblemDetails aufgerufen wird. Dies gilt jedoch nicht, wenn der Accept-HTTP-Anforderungsheader keinen der vom registrierten IProblemDetailsWriter unterstützten Inhaltstyp enthält (Standard: application/json):

Minimal-API-Apps können mithilfe der AddProblemDetails-Erweiterungsmethode so konfiguriert werden, dass sie eine Antwort mit Problemdetails für alle HTTP-Antworten zu Client- und Serverfehlern generieren, die noch keinen Textinhalt aufweisen.

Mit dem folgenden Code wird die App so konfiguriert, dass Problemdetails generiert werden:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Weitere Informationen zur Verwendung von AddProblemDetails finden Sie unter Problemdetails.

IProblemDetailsService-Fallback

Im folgenden Code gibt httpContext.Response.WriteAsync("Fallback: An error occurred.") einen Fehler zurück, wenn die Implementierung von IProblemDetailsService kein ProblemDetails-Element generieren kann:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/exception", () =>
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Der obige Code:

  • Schreibt eine Fehlermeldung mit dem Fallbackcode, wenn ProblemDetails nicht von problemDetailsService geschrieben werden kann. Beispielsweise ein Endpunkt, bei dem der Anforderungsheader für die Annahme einen Medientyp angibt, der von DefaulProblemDetailsWriter nicht unterstützt wird.
  • Nutzt die Middleware für Ausnahmehandler.

Das folgende Beispiel ähnelt dem vorherigen, mit der Ausnahme, dass Status Code Pages middleware aufgerufen wird.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseStatusCodePages(statusCodeHandlerApp =>
{
    statusCodeHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/users/{id:int}", (int id) =>
{
    return id <= 0 ? Results.BadRequest() : Results.Ok(new User(id));
});

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

In diesem Artikel wird beschrieben, wie Sie Fehler in Minimal-API-Apps behandeln.

Ausnahmen

In einer Minimal-API-App gibt es zwei verschiedene integrierte und zentralisierte Verfahren zum Behandeln von Ausnahmefehlern:

In diesem Abschnitt wird auf die folgende Minimal-API-App verwiesen, um Möglichkeiten zum Behandeln von Ausnahmen zu veranschaulichen. Sie löst eine Ausnahme aus, wenn der Endpunkt /exception angefordert wird:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });

app.Run();

Seite mit Ausnahmen für Entwickler

Auf der Seite mit Entwicklerausnahmen werden detaillierte Stapelüberwachungen für Serverfehler angezeigt. Es verwendet DeveloperExceptionPageMiddleware, um synchrone und asynchrone Ausnahmen aus der HTTP-Pipeline zu erfassen und um Fehlerantworten zu generieren.

ASP.NET Core-Apps aktivieren standardmäßig die Seite mit Ausnahmen für Entwickler, wenn die folgenden Aussagen beide zutreffen:

Weitere Informationen zum Konfigurieren von Middleware finden Sie unter Middleware in Minimal-API-Apps.

Wenn Developer Exception Page bei der obigen Minimal-API-App einen Ausnahmefehler erkennt, generiert sie eine Nur-Text-Standardantwort, die dem folgenden Beispiel ähnelt:

HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
Date: Thu, 27 Oct 2022 18:00:59 GMT
Server: Kestrel
Transfer-Encoding: chunked

    System.InvalidOperationException: Sample Exception
    at Program.<>c.<<Main>$>b__0_1() in ....:line 17
    at lambda_method2(Closure, Object, HttpContext)
    at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
    --- End of stack trace from previous location ---
    at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Connection: keep-alive
Host: localhost:5239
Accept-Encoding: gzip, deflate, br

Warnung

Aktivieren Sie die Seite für Entwicklerausnahmen nur, wenn die App in der Entwicklungsumgebung ausgeführt wird. Wenn die App in der Produktionsumgebung ausgeführt wird, sollten Sie keine detaillierten Ausnahmeinformationen öffentlich teilen. Weitere Informationen zum Konfigurieren der Umgebung finden Sie unter Verwenden mehrerer Umgebungen in ASP.NET Core.

Ausnahmehandler

In Nicht-Entwicklungsumgebungen kann Middleware zur Ausnahmebehandlung verwendet werden, um Fehlernutzdaten zu generieren. Rufen Sie UseExceptionHandler auf, um Exception Handler Middleware zu konfigurieren.

Der folgende Code ändert die App beispielsweise so, dass sie dem Client mit RFC 7807-konformen Nutzdaten antwortet. Weitere Informationen finden Sie im Abschnitt zu Problemdetails.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp 
    => exceptionHandlerApp.Run(async context 
        => await Results.Problem()
                     .ExecuteAsync(context)));

app.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });

app.Run();

Client- und Serverfehlerantworten

Betrachten Sie die folgende Minimal-API-App.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.Run();

public record User(int Id);

Der /users-Endpunkt generiert 200 OK mit einer json-Darstellung von User, wenn id größer als 0 ist, und andernfalls den Statuscode 400 BAD REQUEST ohne Antworttext. Weitere Informationen zum Erstellen einer Antwort finden Sie unter Erstellen von Antworten in Minimal-API-Apps.

Status Code Pages middleware kann so konfiguriert werden, dass für alle HTTP-Antworten vom Client (400-499) oder Server (500 -599) ein allgemeiner Textinhalt erzeugt wird, wenn er leer ist. Die Middleware wird durch Aufrufen der UseStatusCodePages-Erweiterungsmethode konfiguriert.

Im folgenden Beispiel wird die App beispielsweise so geändert, dass sie dem Client mit RFC 7807-konformen Nutzdaten für alle Client- und Serverantworten reagiert, einschließlich Routingfehlern (z. B. 404 NOT FOUND). Weitere Informationen finden Sie im Abschnitt zu Problemdetails.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseStatusCodePages(async statusCodeContext 
    =>  await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
                 .ExecuteAsync(statusCodeContext.HttpContext));

app.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.Run();

public record User(int Id);

Problemdetails

Problemdetails sind nicht das einzige Antwortformat zur Beschreibung eines HTTP-API-Fehlers, sie werden jedoch häufig verwendet, um Fehler für HTTP-APIs zu melden.

Der Dienst für Problemdetails implementiert die IProblemDetailsService-Schnittstelle, die das Erstellen von Problemdetails in ASP.NET Core unterstützt. Die Erweiterungsmethode AddProblemDetails(IServiceCollection) in IServiceCollection registriert die Standardimplementierung von IProblemDetailsService.

In ASP.NET Core-Apps generiert die folgende Middleware HTTP-Antworten mit Problemdetails, wenn AddProblemDetails aufgerufen wird. Dies gilt jedoch nicht, wenn der Accept-HTTP-Anforderungsheader keinen der vom registrierten IProblemDetailsWriter unterstützten Inhaltstyp enthält (Standard: application/json):

Minimal-API-Apps können mithilfe der AddProblemDetails-Erweiterungsmethode so konfiguriert werden, dass sie eine Antwort mit Problemdetails für alle HTTP-Antworten zu Client- und Serverfehlern generieren, die noch keinen Textinhalt aufweisen.

Mit dem folgenden Code wird die App so konfiguriert, dass Problemdetails generiert werden:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

app.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });

app.Run();

Weitere Informationen zur Verwendung von AddProblemDetails finden Sie unter Problemdetails.