Freigeben über


Behandeln von Fehlern in ASP.NET Core-APIs

Hinweis

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

Warnung

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

In diesem Artikel wird beschrieben, wie Fehler in ASP.NET Core-APIs behandelt werden. Die Dokumentation für minimale APIs ist ausgewählt. Um die Dokumentation für controllerbasierte APIs anzuzeigen, wählen Sie die Registerkarte "Controller" aus. Blazor Anleitungen zur Fehlerbehandlung finden Sie unter Behandeln von Fehlern in ASP.NET Core-AppsBlazor.

Seite "Entwickler exception"

Auf der Entwickler ausnahmeseite werden detaillierte Informationen zu nicht behandelten Anforderungs ausnahmen angezeigt. Es wird DeveloperExceptionPageMiddleware verwendet, um synchrone und asynchrone Ausnahmen von der HTTP-Pipeline zu erfassen und Fehlerantworten zu generieren. Die Entwickler exception page runs early in the middleware pipeline, so that it can catch unhandled exceptions thrown in middleware that follows.

ASP.NET Core-Apps aktivieren standardmäßig die Entwickler ausnahmeseite, wenn beides:

Apps, die mithilfe früherer Vorlagen erstellt wurden, WebHost.CreateDefaultBuilderkönnen die Entwickler-Ausnahmeseite durch Aufrufen app.UseDeveloperExceptionPageaktivieren.

Warnung

Aktivieren Sie die Entwickler exception Page nicht, es sei denn, die App wird in der Entwicklungsumgebung ausgeführt. Geben Sie keine detaillierten Ausnahmeinformationen öffentlich frei, wenn die App in der Produktion ausgeführt wird. Weitere Informationen zum Konfigurieren von Umgebungen finden Sie unter ASP.NET Core-Laufzeitumgebungen.

Die Entwickler exception page can include the following information about the exception and the request:

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

Die Entwickler exception page isn't guaranteed to provide any information. Verwenden Sie die Protokollierung für vollständige Fehlerinformationen.

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

Entwickler-Ausnahmeseite animiert, um jede ausgewählte Registerkarte anzuzeigen.

Als Reaktion auf eine Anforderung mit einem Accept: text/plain Header gibt die Entwickler-Ausnahmeseite nur Text anstelle von HTML zurück. 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 zeigen Sie die Entwickler ausnahmeseite in einer minimalen API an:

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

Dieser Abschnitt bezieht sich auf die folgende Beispiel-App, um Möglichkeiten zum Behandeln von Ausnahmen in einer minimalen API zu veranschaulichen. Es 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();

Ausnahmehandler

Verwenden Sie in Nicht-Entwicklungsumgebungen die Ausnahmehandler-Middleware , um eine Fehlernutzlast zu erzeugen.

Rufen Sie Exception Handler Middlewarezum Konfigurieren des Aufrufs UseExceptionHandlerauf. Der folgende Code ändert beispielsweise die App so, dass sie mit einer RFC 7807-kompatiblen Nutzlast auf den Client reagiert. 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 Minimale 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 erzeugt 200 OK eine json Darstellung, User wenn id größer als 0ist, andernfalls einen 400 BAD REQUEST Statuscode ohne Antworttext. Weitere Informationen zum Erstellen einer Antwort finden Sie unter Erstellen von Antworten in minimalen API-Apps.

Die Status Code Pages middleware Konfiguration kann so konfiguriert werden, dass für alle HTTP-Clientantworten (400-) oder Server (499500 -) ein allgemeiner Textkörperinhalt erzeugt wird, 599 ist. Die Middleware wird durch Aufrufen der UseStatusCodePages-Erweiterungsmethode konfiguriert.

Im folgenden Beispiel wird die App beispielsweise so geändert, dass sie mit einer RFC 7807-kompatiblen Nutzlast für alle Client- und Serverantworten reagiert, einschließlich Routingfehlern (z 404 NOT FOUND. B. ). Weitere Informationen finden Sie im Abschnitt "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 Problemdetailsdienst implementiert die IProblemDetailsService Schnittstelle, die das Erstellen von Problemdetails in ASP.NET Core unterstützt. Die AddProblemDetails(IServiceCollection) Erweiterungsmethode bei IServiceCollection der Registrierung der Standardimplementierung IProblemDetailsService .

In ASP.NET Core-Apps generiert die folgende Middleware beim Aufruf Http-Antworten AddProblemDetails mit Problemdetails, außer wenn der Accept Anforderungs-HTTP-Header keinen der von der registrierten IProblemDetailsWriter (Standardeinstellung) unterstützten Inhaltstypen enthält: application/json

Minimale API-Apps können so konfiguriert werden, dass die Antwort auf Problemdetails für alle HTTP-Client- und Serverfehlerantworten generiert wird, die noch keinen Textinhalt haben , indem sie die AddProblemDetails Erweiterungsmethode verwenden.

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 AddProblemDetailsfinden Sie unter Problemdetails

IProblemDetailsService-Fallback

Gibt im folgenden Code einen Fehler zurück, wenn die Implementierung nicht in der httpContext.Response.WriteAsync("Fallback: An error occurred.") Lage ist, IProblemDetailsService eine ProblemDetails:

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 vorherige Code:

  • Schreibt eine Fehlermeldung mit dem Fallbackcode, wenn der problemDetailsService Fehler nicht geschrieben ProblemDetailswerden kann. Ein Endpunkt, auf dem der Accept-Anforderungsheader beispielsweise einen Medientyp angibt, der DefaulProblemDetailsWriter nicht unterstützt wird.
  • Verwendet die Middleware des Ausnahmehandlers.

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

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

Zusätzliche Fehlerbehandlungsfeatures

Migration von Controllern zu minimalen APIs

Wenn Sie von controllerbasierten APIs zu minimalen APIs migrieren:

  1. Ersetzen von Aktionsfiltern durch Endpunktfilter oder Middleware
  2. Ersetzen der Modellüberprüfung durch manuelle Überprüfung oder benutzerdefinierte Bindung
  3. Ersetzen von Ausnahmefiltern durch Middleware für die Ausnahmebehandlung
  4. Konfigurieren von Problemdetails mithilfe konsistenter AddProblemDetails() Fehlerantworten

Gründe für die Verwendung der controllerbasierten Fehlerbehandlung

Berücksichtigen Sie bei Bedarf controllerbasierte APIs:

  • Komplexe Modellüberprüfungsszenarien
  • Zentralisierte Ausnahmebehandlung über mehrere Controller hinweg
  • Feinkörnige Kontrolle über die Fehlerantwortformatierung
  • Integration in MVC-Features wie Filter und Konventionen

Ausführliche Informationen zur controllerbasierten Fehlerbehandlung, einschließlich Validierungsfehlern, Anpassung von Problemen und Ausnahmefiltern, finden Sie in den Registerkartenabschnitten " Controller ".

Weitere Ressourcen