Behandeln von Fehlern in Minimal-API-Apps

Hinweis

Dies ist nicht die neueste Version dieses Artikels. 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.

Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Mit Beiträgen von David Acker

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.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /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.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 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 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.