Fehlerbehandlung in ASP.NET Core
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.
Von Tom Dykstra
Dieser Artikel beschreibt grundsätzliche Vorgehensweisen zur Behandlung von Fehlern in ASP.NET Core-Web-Apps. Weitere Informationen finden Sie auch unter Fehlerbehandlung in ASP.NET Core-Web-APIs und Behandeln von Fehlern in Minimal-API-Apps.
Anleitungen zur Fehlerbehandlung in Blazor, die die Anleitungen in diesem Artikel ergänzen oder ersetzen, finden Sie unter Fehlerbehandlung in ASP.NET Core-Blazor-Apps.
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:
- Die Ausführung erfolgt in der Entwicklungsumgebung.
- Die App wurde mit den aktuellen Vorlagen erstellt, d. h. mithilfe von WebApplication.CreateBuilder.
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:
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
Seite „Ausnahmehandler“
Um eine benutzerdefinierte Fehlerbehandlungsseite für die Produktionsumgebung zu konfigurieren, rufen Sie UseExceptionHandler auf. Die Aufgaben der Middleware zur Ausnahmebehandlung:
- Dient zum Abfangen und Protokollieren unbehandelter Ausnahmen.
- Führt erneut die Anforderung in einer anderen Pipeline im angegebenen Pfad aus. Die Anforderung wird nicht erneut ausgeführt, wenn die Antwort gestartet wurde. Der von der Vorlage generierte Code führt die Anforderung erneut mit dem
/Error
-Pfad aus.
Warnung
Wenn die alternative Pipeline eigenständig eine Ausnahme auslöst, löst die Middleware für die Ausnahmebehandlung erneut die ursprüngliche Ausnahme aus.
Da diese Middleware die Anforderungspipeline erneut ausführen kann, gilt Folgendes:
- Middlewares müssen die erneute Ausführung mit derselben Anforderung verarbeiten. Dies bedeutet normalerweise, dass ihr Zustand nach dem Aufrufen von
_next
bereinigt oder die Verarbeitung imHttpContext
zwischengespeichert wird, um eine Wiederholung zu vermeiden. Bei der Verarbeitung des Anforderungstexts bedeutet dies, dass Ergebnisse wie beispielsweise der Formularleser entweder gepuffert oder zwischengespeichert werden. - Für die UseExceptionHandler(IApplicationBuilder, String)-Überladung, die in Vorlagen verwendet wird, wird nur der Anforderungspfad geändert, und die Routendaten werden gelöscht. Anforderungsdaten wie Header, Methoden und Elemente werden unverändert wiederverwendet.
- Bereichsbezogene Dienste bleiben gleich.
Im folgenden Beispiel fügt UseExceptionHandler die Middleware zur Ausnahmebehandlung in Nichtentwicklungsumgebungen hinzu:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Die Razor Pages-App-Vorlage stellt im Ordner Pages eine Fehlerseite (.cshtml
) und eine PageModel-Klasse (ErrorModel
) bereit. Die Projektvorlage für eine MVC-App enthält eine Error
-Aktionsmethode und eine Fehleransicht für den Home-Controller.
Die Middleware für die Ausnahmebehandlung führt die Anforderung unter Verwendung der ursprünglichen HTTP-Methode erneut aus. Wenn ein Endpunkt für die Fehlerbehandlung auf bestimmte HTTP-Methoden beschränkt ist, wird er nur für diese Methoden ausgeführt. Beispielsweise wird eine MVC-Controller-Aktion, die das Attribut [HttpGet]
verwendet, nur für GET-Anforderungen ausgeführt. Um sicherzustellen, dass alle Anforderungen die benutzerdefinierte Seite für die Fehlerbehandlung erreichen, beschränken Sie die Endpunkte nicht auf bestimmte HTTP-Methoden.
So behandeln Sie Ausnahmen unterschiedlich, basierend auf der ursprünglichen HTTP-Methode:
- Für Razor Pages erstellen Sie mehrere Handlermethoden. Verwenden Sie beispielsweise
OnGet
zum Behandeln von GET-Ausnahmen undOnPost
zum Behandeln von POST-Ausnahmen. - Für MVC wenden Sie HTTP-Verbattribute auf mehrere Aktionen an. Verwenden Sie beispielsweise
[HttpGet]
zum Behandeln von GET-Ausnahmen und[HttpPost]
zum Behandeln von POST-Ausnahmen.
Um nicht authentifizierten Benutzern die Anzeige der benutzerdefinierten Seite für die Fehlerbehandlung zu ermöglichen, stellen Sie sicher, dass der anonyme Zugriff unterstützt wird.
Zugreifen auf die Ausnahme
Verwenden Sie IExceptionHandlerPathFeature, um auf die Ausnahme oder den Pfad der ursprünglichen Anforderung in einem Fehlerhandler zuzugreifen. Im folgenden Beispiel wird IExceptionHandlerPathFeature
verwendet, um weitere Informationen zur ausgelösten Ausnahme zu erhalten:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "The file was not found.";
}
if (exceptionHandlerPathFeature?.Path == "/")
{
ExceptionMessage ??= string.Empty;
ExceptionMessage += " Page: Home.";
}
}
}
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
Lambda-Ausdruck für Ausnahmehandler
Eine Alternative zu einer benutzerdefinierten Ausnahmebehandlungsseite ist das Angeben eines Lambda-Ausdrucks für UseExceptionHandler. Die Verwendung eines Lambda-Ausdrucks ermöglicht den Zugriff auf den Fehler, bevor die Antwort zurückgegeben wird.
Der folgende Code verwendet einen Lambdaausdruck für die Ausnahmebehandlung:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
Eine andere Möglichkeit, ein Lambda zu verwenden, besteht darin, den Statuscode auf der Grundlage des Ausnahmetyps festzulegen, wie im folgenden Beispiel:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseExceptionHandler(new ExceptionHandlerOptions
{
StatusCodeSelector = ex => ex is TimeoutException
? StatusCodes.Status503ServiceUnavailable
: StatusCodes.Status500InternalServerError
});
}
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
IExceptionHandler
IExceptionHandler ist eine Schnittstelle, die dem Entwickler die Möglichkeit zum Rückruf und Behandeln bekannter Ausnahmen an einem zentralen Ort bietet.
IExceptionHandler
-Implementierungen werden durch Aufrufen von IServiceCollection.AddExceptionHandler<T>
registriert. Die Lebensdauer einer IExceptionHandler
-Instanz ist Singleton. Es können mehrere Implementierungen hinzugefügt werden, die in der registrierten Reihenfolge aufgerufen werden.
Wenn ein Ausnahmehandler eine Anforderung verarbeitet, kann er true
zurückgeben, um die Verarbeitung zu beenden. Wenn eine Ausnahme von keinem Ausnahmehandler behandelt wird, greift das Steuerelement auf das Standardverhalten und die Standardoptionen der Middleware zurück. Für behandelte und nicht behandelte Ausnahmen werden unterschiedliche Metriken und Protokolle ausgegeben.
Das folgende Beispiel zeigt eine Implementierung von IExceptionHandler
:
using Microsoft.AspNetCore.Diagnostics;
namespace ErrorHandlingSample
{
public class CustomExceptionHandler : IExceptionHandler
{
private readonly ILogger<CustomExceptionHandler> logger;
public CustomExceptionHandler(ILogger<CustomExceptionHandler> logger)
{
this.logger = logger;
}
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
var exceptionMessage = exception.Message;
logger.LogError(
"Error Message: {exceptionMessage}, Time of occurrence {time}",
exceptionMessage, DateTime.UtcNow);
// Return false to continue with the default behavior
// - or - return true to signal that this exception is handled
return ValueTask.FromResult(false);
}
}
}
Das folgende Beispiel zeigt, wie Sie eine IExceptionHandler
-Implementierung für die Abhängigkeitsinjektion registrieren:
using ErrorHandlingSample;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
builder.Services.AddExceptionHandler<CustomExceptionHandler>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// Remaining Program.cs code omitted for brevity
Wenn der vorherige Code in der Entwicklungsumgebung ausgeführt wird:
- Zuerst wird
CustomExceptionHandler
aufgerufen, um eine Ausnahme zu behandeln. - Nach der Protokollierung der Ausnahme gibt die
TryHandleAsync
-Methodefalse
zurück, sodass die Entwickler-Ausnahmeseite angezeigt wird.
In anderen Umgebungen:
- Zuerst wird
CustomExceptionHandler
aufgerufen, um eine Ausnahme zu behandeln. - Nach der Protokollierung der Ausnahme gibt die
TryHandleAsync
-Methodefalse
zurück, sodass die/Error
-Seite angezeigt wird.
UseStatusCodePages
Die ASP.NET Core-App stellt für HTTP-Fehlerstatuscodes wie 404 – Nicht gefunden standardmäßig keine Statuscodeseite zur Verfügung. Wenn die App einen HTTP-Fehlerstatuscode im Bereich 400 bis 599 ohne Text festlegt, werden der Statuscode und ein leerer Antworttext zurückgegeben. Um für gängige Statuscodes einfache Handler im Textformat zu aktivieren, rufen Sie UseStatusCodePages in Program.cs
auf:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Rufen Sie UseStatusCodePages
vor der Middleware für die Anforderungsverarbeitung auf. Rufen Sie beispielsweise UseStatusCodePages
vor der Middleware für statische Dateien und der Middleware für Endpunkte auf.
Wenn UseStatusCodePages
nicht verwendet wird, wird beim Navigieren zu einer URL ohne Endpunkt eine browserabhängige Fehlermeldung zurückgegeben, die angibt, dass der Endpunkt nicht gefunden werden kann. Wenn UseStatusCodePages
aufgerufen wird, gibt der Browser die folgende Antwort zurück:
Status Code: 404; Not Found
UseStatusCodePages
wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
Hinweis
Die Middleware für Statuscodeseiten erfasst keine Ausnahmen. Um eine benutzerdefinierte Fehlerbehandlungsseite bereitzustellen, verwenden Sie die Ausnahmehandlerseite.
UseStatusCodePages mit Formatzeichenfolge
Um den Inhaltstyp und Text der Antwort anzupassen, verwenden Sie die Überladung von UseStatusCodePages, die einen Inhaltstyp und eine Formatierungszeichenfolge erfordert:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// using static System.Net.Mime.MediaTypeNames;
app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");
Im vorangehenden Code ist {0}
ein Platzhalter für den Fehlercode.
UseStatusCodePages
mit Formatzeichenfolge wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
UseStatusCodePages mit Lambda-Ausdruck
Um benutzerdefinierten Code für die Fehlerbehandlung und das Schreiben von Antworten anzugeben, verwenden Sie die Überladung von UseStatusCodePages, die einen Lambda-Ausdruck verwendet:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async statusCodeContext =>
{
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
$"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});
UseStatusCodePages
mit Lambdaausdruck wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
UseStatusCodePagesWithRedirects
Die Erweiterungsmethode UseStatusCodePagesWithRedirects:
- Sendet den Statuscode 302 Found (Gefunden) an den Client.
- Leitet den Client an den in der URL-Vorlage angegebenen Fehlerbehandlungsendpunkt weiter. Der Fehlerbehandlungsendpunkt zeigt in der Regel Fehlerinformationen an und gibt den HTTP-Code 200 zurück.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Die URL-Vorlage kann, wie im vorangehenden Code gezeigt, einen {0}
-Platzhalter für den Statuscode enthalten. Wenn die URL-Vorlage mit einer Tilde (~
) beginnt, wird ~
durch die Angabe für PathBase
der App ersetzt. Wenn Sie in der App einen Endpunkt angeben, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Den Client an einen anderen Endpunkt umleiten, in der Regel in Fällen, in denen eine andere App den Fehler verarbeitet. Für Web-Apps gibt die Adressleiste des Browsers des Clients den umgeleiteten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der anfänglichen Umleitungsantwort nicht beibehalten und zurückgeben.
UseStatusCodePagesWithReExecute
Die Erweiterungsmethode UseStatusCodePagesWithReExecute:
- Generiert den Antworttext durch die erneute Ausführung der Anforderungspipeline mithilfe eines alternativen Pfads.
- Ändert den Statuscode nicht vor oder nach der erneuten Ausführung der Pipeline.
Die neue Pipelineausführung kann den Statuscode der Antwort ändern, da sie die vollständige Kontrolle über den Statuscode hat. Wenn die neue Pipeline den Statuscode nicht ändert, wird der ursprüngliche Statuscode an den Client gesendet.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Wenn in der App ein Endpunkt angegeben ist, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Die Anforderung ohne Umleitung an einen anderen Endpunkt verarbeiten. Für Web-Apps gibt die Adressleiste des Browsers des Clients den ursprünglich angeforderten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der Antwort beibehalten und zurückgeben.
Die URL-Vorlage muss mit /
beginnen und kann den Platzhalter {0}
für den Statuscode enthalten. Um den Statuscode als Abfragezeichenfolgenparameter zu übergeben, übergeben Sie ein zweites Argument an UseStatusCodePagesWithReExecute
. Beispiel:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Der Endpunkt, der den Fehler verarbeitet, kann die ursprüngliche URL abrufen, die den Fehler generiert hat (siehe folgendes Beispiel):
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = $"{statusCodeReExecuteFeature.OriginalPathBase}"
+ $"{statusCodeReExecuteFeature.OriginalPath}"
+ $"{statusCodeReExecuteFeature.OriginalQueryString}";
}
}
}
Da diese Middleware die Anforderungspipeline erneut ausführen kann, gilt Folgendes:
- Middlewares müssen die erneute Ausführung mit derselben Anforderung verarbeiten. Dies bedeutet normalerweise, dass ihr Zustand nach dem Aufrufen von
_next
bereinigt oder die Verarbeitung imHttpContext
zwischengespeichert wird, um eine Wiederholung zu vermeiden. Bei der Verarbeitung des Anforderungstexts bedeutet dies, dass Ergebnisse wie beispielsweise der Formularleser entweder gepuffert oder zwischengespeichert werden. - Bereichsbezogene Dienste bleiben gleich.
Deaktivieren von Statuscodeseiten
Verwenden Sie das Attribut [SkipStatusCodePages], um Statuscodeseiten für einen MVC-Controller oder eine MVC-Aktionsmethode zu deaktivieren.
Verwenden Sie IStatusCodePagesFeature, um Statuscodeseiten für bestimmte Anforderungen in der Handlermethode von Razor Pages oder in einem MVC-Controller zu deaktivieren:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Ausnahmebehandlungscode
Code auf Seiten zur Ausnahmebehandlung kann ebenfalls Ausnahmen auslösen. Produktionsfehlerseiten sollten gründlich getestet werden. Achten Sie darauf, dabei keine eigenen Ausnahmen auszulösen.
Antwortheader
Nachdem die Header für eine Antwort gesendet wurden:
- Die App kann den Statuscode der Antwort nicht ändern.
- Weder Ausnahmeseiten noch Handler können ausgeführt werden. Die Antwort muss abgeschlossen oder die Verbindung unterbrochen werden.
Sichere Ausnahmebehandlung
Neben der Ausnahmebehandlungslogik in einer App kann die HTTP-Serverimplementierung einige Ausnahmebehandlungen durchführen. Wenn der Server eine Ausnahme erfasst, bevor die Antwortheader gesendet werden, sendet der Server die Antwort 500 - Internal Server Error
ohne Antworttext. Wenn der Server eine Ausnahme auffängt, nachdem die Antwortheader gesendet wurden, schließt der Server die Verbindung. Anforderungen, die nicht von der App verarbeitet werden, werden vom Server verarbeitet. Jede Ausnahme, die bei der Anforderungsverarbeitung durch den Server auftritt, wird durch die Ausnahmebehandlung des Servers verarbeitet. Die benutzerdefinierten Fehlerseiten der App, Middleware zur Fehlerbehandlung und Filter haben keine Auswirkungen auf dieses Verhalten.
Fehlerbehandlung während des Starts
Nur auf Hostebene können Ausnahmen behandelt werden, die während des Starts einer App auftreten. Der Host kann für das Erfassen von Startfehlern und Erfassen detaillierter Fehler konfiguriert werden.
Die Hostingebene kann nur dann für einen beim Start erfassten Fehler eine Fehlerseite anzeigen, wenn der Fehler nach der Bindung an die Hostadresse bzw. den Port auftritt. Wenn die Bindung misslingt:
- Die Hostebene protokolliert eine kritische Ausnahme.
- Der DotNet-Prozess stürzt ab.
- Wenn der HTTP-Server Kestrel heißt, wird keine Fehlerseite angezeigt.
Wenn sie auf IIS (oder Azure App Service) oder IIS Express ausgeführt wird, wird ein Prozessfehler 502.5 vom ASP.NET Core-Modul zurückgegeben, wenn der Prozess nicht starten kann. Weitere Informationen finden Sie unter Problembehandlung bei ASP.NET Core in Azure App Service und IIS.
Datenbank-Fehlerseite
Der Ausnahmefilter der Datenbankentwicklerseite AddDatabaseDeveloperPageExceptionFilter erfasst datenbankbezogene Ausnahmen, die mithilfe von Entity Framework Core-Migrationen aufgelöst werden können. Wenn diese Ausnahmen auftreten, wird eine HTML-Antwort mit Details zu möglichen Aktionen zum Beheben des Problems generiert. Diese Seite ist nur in der Entwicklungsumgebung aktiviert. Der folgende Code fügt den Ausnahmefilter der Datenbankentwicklerseite hinzu:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Ausnahmefilter
In MVC-Apps können Ausnahmefilter global oder auf einen Controller oder eine Aktion bezogen konfiguriert werden. In Razor Pages-Apps können sie global oder auf ein Seitenmodell bezogen konfiguriert werden. Diese Filter verarbeiten jede nicht behandelte Ausnahme, die während der Ausführung eine Controlleraktion oder eines anderen Filters auftritt. Weitere Informationen finden Sie unter Filter in ASP.NET Core.
Ausnahmefilter eignen sich zum Auffangen von Ausnahmen, die in MVC-Aktionen ausgelöst werden. Sie sind jedoch nicht so flexibel wie die integrierte Middleware für die Ausnahmebehandlung, UseExceptionHandler. Es wird empfohlen, UseExceptionHandler
zu verwenden, wenn Sie für die Fehlerbehandlung auf Grundlage einer ausgewählten MVC-Aktion eine andere Strategie auswählen müssen.
Modellstatusfehler
Informationen zum Behandeln von Modellstatusfehlern finden Sie unter Modellbindung und Modellvalidierung.
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
):
- ExceptionHandlerMiddleware generiert eine Problemdetailantwort, wenn kein benutzerdefinierter Handler definiert ist.
- StatusCodePagesMiddleware generiert standardmäßig eine Problemdetailantwort.
- DeveloperExceptionPageMiddleware generiert eine Problemdetailantwort während der Entwicklungsphase, wenn der
Accept
-HTTP-Anforderungsheader nichttext/html
enthält.
Mit dem folgenden Code wird die App so konfiguriert, dass eine Problemdetailantwort für alle Fehlerantworten von HTTP-Client und -Server generiert wird, die noch keinen Textinhalt aufweisen:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Im nächsten Abschnitt wird gezeigt, wie Sie den Antworttext mit den Problemdetails anpassen.
Anpassen von Problemdetails
Die automatische Erstellung von ProblemDetails
kann mit einer der folgenden Optionen angepasst werden:
- Verwenden Sie
ProblemDetailsOptions.CustomizeProblemDetails
- Verwenden einer benutzerdefinierten
IProblemDetailsWriter
-Datei - Aufrufen von
IProblemDetailsService
in einer Middleware
CustomizeProblemDetails
Vorgang
Die generierten Problemdetails können mithilfe von CustomizeProblemDetails angepasst werden, und die Anpassungen werden auf alle automatisch generierten Problemdetails angewandt.
Der folgende Code verwendet ProblemDetailsOptions, um CustomizeProblemDetails festzulegen:
builder.Services.AddProblemDetails(options =>
options.CustomizeProblemDetails = ctx =>
ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Beispielsweise erzeugt ein HTTP Status 400 Bad Request
-Endpunkt den folgenden Antworttext mit Problemdetails:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Benutzerdefinierter IProblemDetailsWriter
Eine IProblemDetailsWriter-Implementierung kann für erweiterte Anpassungen erstellt werden.
public class SampleProblemDetailsWriter : IProblemDetailsWriter
{
// Indicates that only responses with StatusCode == 400
// are handled by this writer. All others are
// handled by different registered writers if available.
public bool CanWrite(ProblemDetailsContext context)
=> context.HttpContext.Response.StatusCode == 400;
public ValueTask WriteAsync(ProblemDetailsContext context)
{
// Additional customizations.
// Write to the response.
var response = context.HttpContext.Response;
return new ValueTask(response.WriteAsJsonAsync(context.ProblemDetails));
}
}
Hinweis: Wenn Sie einen benutzerdefinierten IProblemDetailsWriter
verwenden, muss der benutzerdefinierte IProblemDetailsWriter
vor dem Aufrufen von AddRazorPages, AddControllers, AddControllersWithViews oder AddMvc registriert werden:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTransient<IProblemDetailsWriter, SampleProblemDetailsWriter>();
var app = builder.Build();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsWriter>() is
{ } problemDetailsService)
{
if (problemDetailsService.CanWrite(new ProblemDetailsContext() { HttpContext = context }))
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.Run();
Problemdetails von Middleware
Ein alternativer Ansatz zur Verwendung von ProblemDetailsOptions mit CustomizeProblemDetails ist das Festlegen von ProblemDetails in Middleware. Eine Problemdetailantwort kann durch Aufrufen von IProblemDetailsService.WriteAsync
geschrieben werden:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStatusCodePages();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.DivisionByZeroError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.NegativeRadicandError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.MapControllers();
app.Run();
Im obigen Code geben die Minimal-API-Endpunkte /divide
und /squareroot
bei einer Fehlereingabe die erwartete benutzerdefinierte Problemantwort zurück.
Die API-Controllerendpunkte geben bei einer Fehlereingabe die Standardproblemantwort zurück, nicht die benutzerdefinierte Problemantwort. Die Standardproblemantwort wird zurückgegeben, da der API-Controller in den Antwortdatenstrom (Problemdetails für Fehlerstatuscodes) geschrieben hat, bevor IProblemDetailsService.WriteAsync
aufgerufen wird, und die Antwort nicht erneut geschrieben wird.
Der folgende ValuesController
gibt BadRequestResult zurück, das in den Antwortdatenstrom geschrieben wird. Damit wird verhindert, dass die benutzerdefinierte Problemantwort zurückgegeben wird.
[Route("api/[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
// /api/values/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Numerator / Denominator);
}
// /api/values/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Math.Sqrt(radicand));
}
}
Der folgende Values3Controller
gibt ControllerBase.Problem
zurück, sodass das erwartete Ergebnis für das benutzerdefinierte Problem zurückgegeben wird:
[Route("api/[controller]/[action]")]
[ApiController]
public class Values3Controller : ControllerBase
{
// /api/values3/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Divison by zero is not defined.",
type: "https://en.wikipedia.org/wiki/Division_by_zero",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Numerator / Denominator);
}
// /api/values3/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Negative or complex numbers are not valid input.",
type: "https://en.wikipedia.org/wiki/Square_root",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Math.Sqrt(radicand));
}
}
Erstellen von ProblemDetails-Nutzdaten für Ausnahmen
Betrachten Sie die folgende App:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapControllers();
app.Run();
Wenn in Nicht-Entwicklungsumgebungen eine Ausnahme auftritt, wird die folgende standardmäßige ProblemDetails-Antwort an den Client zurückgegeben:
{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500,"traceId":"00-b644<snip>-00"
}
Für die meisten Apps ist für Ausnahmen nur der oben stehende Code erforderlich. Der folgende Abschnitt zeigt jedoch, wie Sie detailliertere Problemantworten erhalten.
Eine Alternative zu einer benutzerdefinierten Ausnahmebehandlungsseite ist das Angeben eines Lambda-Ausdrucks für UseExceptionHandler. Die Verwendung einer Lambdafunktion ermöglicht den Zugriff auf den Fehler und das Schreiben einer Problemdetailantwort mit IProblemDetailsService.WriteAsync
:
using Microsoft.AspNetCore.Diagnostics;
using static System.Net.Mime.MediaTypeNames;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = Text.Plain;
var title = "Bad Input";
var detail = "Invalid input";
var type = "https://errors.example.com/badInput";
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
var exceptionHandlerFeature =
context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType != null &&
exceptionType.Message.Contains("infinity"))
{
title = "Argument exception";
detail = "Invalid input";
type = "https://errors.example.com/argumentException";
}
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = title,
Detail = detail,
Type = type
}
});
}
});
});
}
app.MapControllers();
app.Run();
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
Ein alternativer Ansatz zum Generieren von Problemdetails besteht darin, das Drittanbieter-NuGet-Paket Hellang.Middleware.ProblemDetails zu verwenden, mit dem Ausnahmen und Clientfehler zu Problemdetails zugeordnet werden können.
Zusätzliche Ressourcen
- Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)
- Problembehandlung bei ASP.NET Core in Azure App Service und IIS
- Problembehandlung für häufige Fehler bei Azure App Service und IIS mit ASP.NET Core
- Behandeln von Fehlern in ASP.NET Core-controllerbasierten Web-APIs
- Behandeln von Fehlern in Minimal-API-Apps
Von Tom Dykstra
Dieser Artikel beschreibt grundsätzliche Vorgehensweisen zur Behandlung von Fehlern in ASP.NET Core-Web-Apps. Weitere Informationen finden Sie auch unter Fehlerbehandlung in ASP.NET Core-Web-APIs und Behandeln von Fehlern in Minimal-API-Apps.
Seite mit Ausnahmen für Entwickler
Die Seite mit Ausnahmen für Entwickler enthält ausführliche Informationen zu unbehandelten Anforderungsausnahmen. ASP.NET Core-Apps aktivieren standardmäßig die Seite mit Ausnahmen für Entwickler, wenn die folgenden Aussagen beide zutreffen:
- Die Ausführung erfolgt in der Entwicklungsumgebung.
- Die App wird mit den aktuellen Vorlagen erstellt, also mit WebApplication.CreateBuilder. Apps, die mithilfe von
WebHost.CreateDefaultBuilder
erstellt wurden, müssen die Seite mit den Ausnahmeseite für Entwickler durch Aufrufen vonapp.UseDeveloperExceptionPage
inConfigure
aktivieren.
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.
Bei Ausführung der App in der Produktionsumgebung dürfen keine detaillierten Informationen zu den Ausnahmen öffentlich angezeigt werden. 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
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.
Seite „Ausnahmehandler“
Um eine benutzerdefinierte Fehlerbehandlungsseite für die Produktionsumgebung zu konfigurieren, rufen Sie UseExceptionHandler auf. Die Aufgaben der Middleware zur Ausnahmebehandlung:
- Dient zum Abfangen und Protokollieren unbehandelter Ausnahmen.
- Führt erneut die Anforderung in einer anderen Pipeline im angegebenen Pfad aus. Die Anforderung wird nicht erneut ausgeführt, wenn die Antwort gestartet wurde. Der von der Vorlage generierte Code führt die Anforderung erneut mit dem
/Error
-Pfad aus.
Warnung
Wenn die alternative Pipeline eigenständig eine Ausnahme auslöst, löst die Middleware für die Ausnahmebehandlung erneut die ursprüngliche Ausnahme aus.
Da diese Middleware die Anforderungspipeline erneut ausführen kann, gilt Folgendes:
- Middlewares müssen die erneute Ausführung mit derselben Anforderung verarbeiten. Dies bedeutet normalerweise, dass ihr Zustand nach dem Aufrufen von
_next
bereinigt oder die Verarbeitung imHttpContext
zwischengespeichert wird, um eine Wiederholung zu vermeiden. Bei der Verarbeitung des Anforderungstexts bedeutet dies, dass Ergebnisse wie beispielsweise der Formularleser entweder gepuffert oder zwischengespeichert werden. - Für die UseExceptionHandler(IApplicationBuilder, String)-Überladung, die in Vorlagen verwendet wird, wird nur der Anforderungspfad geändert, und die Routendaten werden gelöscht. Anforderungsdaten wie Header, Methoden und Elemente werden unverändert wiederverwendet.
- Bereichsbezogene Dienste bleiben gleich.
Im folgenden Beispiel fügt UseExceptionHandler die Middleware zur Ausnahmebehandlung in Nichtentwicklungsumgebungen hinzu:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Die Razor Pages-App-Vorlage stellt im Ordner Pages eine Fehlerseite (.cshtml
) und eine PageModel-Klasse (ErrorModel
) bereit. Die Projektvorlage für eine MVC-App enthält eine Error
-Aktionsmethode und eine Fehleransicht für den Home-Controller.
Die Middleware für die Ausnahmebehandlung führt die Anforderung unter Verwendung der ursprünglichen HTTP-Methode erneut aus. Wenn ein Endpunkt für die Fehlerbehandlung auf bestimmte HTTP-Methoden beschränkt ist, wird er nur für diese Methoden ausgeführt. Beispielsweise wird eine MVC-Controller-Aktion, die das Attribut [HttpGet]
verwendet, nur für GET-Anforderungen ausgeführt. Um sicherzustellen, dass alle Anforderungen die benutzerdefinierte Seite für die Fehlerbehandlung erreichen, beschränken Sie die Endpunkte nicht auf bestimmte HTTP-Methoden.
So behandeln Sie Ausnahmen unterschiedlich, basierend auf der ursprünglichen HTTP-Methode:
- Für Razor Pages erstellen Sie mehrere Handlermethoden. Verwenden Sie beispielsweise
OnGet
zum Behandeln von GET-Ausnahmen undOnPost
zum Behandeln von POST-Ausnahmen. - Für MVC wenden Sie HTTP-Verbattribute auf mehrere Aktionen an. Verwenden Sie beispielsweise
[HttpGet]
zum Behandeln von GET-Ausnahmen und[HttpPost]
zum Behandeln von POST-Ausnahmen.
Um nicht authentifizierten Benutzern die Anzeige der benutzerdefinierten Seite für die Fehlerbehandlung zu ermöglichen, stellen Sie sicher, dass der anonyme Zugriff unterstützt wird.
Zugreifen auf die Ausnahme
Verwenden Sie IExceptionHandlerPathFeature, um auf die Ausnahme oder den Pfad der ursprünglichen Anforderung in einem Fehlerhandler zuzugreifen. Im folgenden Beispiel wird IExceptionHandlerPathFeature
verwendet, um weitere Informationen zur ausgelösten Ausnahme zu erhalten:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "The file was not found.";
}
if (exceptionHandlerPathFeature?.Path == "/")
{
ExceptionMessage ??= string.Empty;
ExceptionMessage += " Page: Home.";
}
}
}
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
Lambda-Ausdruck für Ausnahmehandler
Eine Alternative zu einer benutzerdefinierten Ausnahmebehandlungsseite ist das Angeben eines Lambda-Ausdrucks für UseExceptionHandler. Die Verwendung eines Lambda-Ausdrucks ermöglicht den Zugriff auf den Fehler, bevor die Antwort zurückgegeben wird.
Der folgende Code verwendet einen Lambdaausdruck für die Ausnahmebehandlung:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
IExceptionHandler
IExceptionHandler ist eine Schnittstelle, die dem Entwickler die Möglichkeit zum Rückruf und Behandeln bekannter Ausnahmen an einem zentralen Ort bietet.
IExceptionHandler
-Implementierungen werden durch Aufrufen von IServiceCollection.AddExceptionHandler<T>
registriert. Die Lebensdauer einer IExceptionHandler
-Instanz ist Singleton. Es können mehrere Implementierungen hinzugefügt werden, die in der registrierten Reihenfolge aufgerufen werden.
Wenn ein Ausnahmehandler eine Anforderung verarbeitet, kann er true
zurückgeben, um die Verarbeitung zu beenden. Wenn eine Ausnahme von keinem Ausnahmehandler behandelt wird, greift das Steuerelement auf das Standardverhalten und die Standardoptionen der Middleware zurück. Für behandelte und nicht behandelte Ausnahmen werden unterschiedliche Metriken und Protokolle ausgegeben.
Das folgende Beispiel zeigt eine Implementierung von IExceptionHandler
:
using Microsoft.AspNetCore.Diagnostics;
namespace ErrorHandlingSample
{
public class CustomExceptionHandler : IExceptionHandler
{
private readonly ILogger<CustomExceptionHandler> logger;
public CustomExceptionHandler(ILogger<CustomExceptionHandler> logger)
{
this.logger = logger;
}
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
var exceptionMessage = exception.Message;
logger.LogError(
"Error Message: {exceptionMessage}, Time of occurrence {time}",
exceptionMessage, DateTime.UtcNow);
// Return false to continue with the default behavior
// - or - return true to signal that this exception is handled
return ValueTask.FromResult(false);
}
}
}
Das folgende Beispiel zeigt, wie Sie eine IExceptionHandler
-Implementierung für die Abhängigkeitsinjektion registrieren:
using ErrorHandlingSample;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
builder.Services.AddExceptionHandler<CustomExceptionHandler>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// Remaining Program.cs code omitted for brevity
Wenn der vorherige Code in der Entwicklungsumgebung ausgeführt wird:
- Zuerst wird
CustomExceptionHandler
aufgerufen, um eine Ausnahme zu behandeln. - Nach der Protokollierung der Ausnahme gibt die
TryHandleException
-Methodefalse
zurück, sodass die Entwickler-Ausnahmeseite angezeigt wird.
In anderen Umgebungen:
- Zuerst wird
CustomExceptionHandler
aufgerufen, um eine Ausnahme zu behandeln. - Nach der Protokollierung der Ausnahme gibt die
TryHandleException
-Methodefalse
zurück, sodass die/Error
-Seite angezeigt wird.
UseStatusCodePages
Die ASP.NET Core-App stellt für HTTP-Fehlerstatuscodes wie 404 – Nicht gefunden standardmäßig keine Statuscodeseite zur Verfügung. Wenn die App einen HTTP-Fehlerstatuscode im Bereich 400 bis 599 ohne Text festlegt, werden der Statuscode und ein leerer Antworttext zurückgegeben. Um für gängige Statuscodes einfache Handler im Textformat zu aktivieren, rufen Sie UseStatusCodePages in Program.cs
auf:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Rufen Sie UseStatusCodePages
vor der Middleware für die Anforderungsverarbeitung auf. Rufen Sie beispielsweise UseStatusCodePages
vor der Middleware für statische Dateien und der Middleware für Endpunkte auf.
Wenn UseStatusCodePages
nicht verwendet wird, wird beim Navigieren zu einer URL ohne Endpunkt eine browserabhängige Fehlermeldung zurückgegeben, die angibt, dass der Endpunkt nicht gefunden werden kann. Wenn UseStatusCodePages
aufgerufen wird, gibt der Browser die folgende Antwort zurück:
Status Code: 404; Not Found
UseStatusCodePages
wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
Hinweis
Die Middleware für Statuscodeseiten erfasst keine Ausnahmen. Um eine benutzerdefinierte Fehlerbehandlungsseite bereitzustellen, verwenden Sie die Ausnahmehandlerseite.
UseStatusCodePages mit Formatzeichenfolge
Um den Inhaltstyp und Text der Antwort anzupassen, verwenden Sie die Überladung von UseStatusCodePages, die einen Inhaltstyp und eine Formatierungszeichenfolge erfordert:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// using static System.Net.Mime.MediaTypeNames;
app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");
Im vorangehenden Code ist {0}
ein Platzhalter für den Fehlercode.
UseStatusCodePages
mit Formatzeichenfolge wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
UseStatusCodePages mit Lambda-Ausdruck
Um benutzerdefinierten Code für die Fehlerbehandlung und das Schreiben von Antworten anzugeben, verwenden Sie die Überladung von UseStatusCodePages, die einen Lambda-Ausdruck verwendet:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async statusCodeContext =>
{
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
$"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});
UseStatusCodePages
mit Lambdaausdruck wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
UseStatusCodePagesWithRedirects
Die Erweiterungsmethode UseStatusCodePagesWithRedirects:
- Sendet den Statuscode 302 Found (Gefunden) an den Client.
- Leitet den Client an den in der URL-Vorlage angegebenen Fehlerbehandlungsendpunkt weiter. Der Fehlerbehandlungsendpunkt zeigt in der Regel Fehlerinformationen an und gibt den HTTP-Code 200 zurück.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Die URL-Vorlage kann, wie im vorangehenden Code gezeigt, einen {0}
-Platzhalter für den Statuscode enthalten. Wenn die URL-Vorlage mit einer Tilde (~
) beginnt, wird ~
durch die Angabe für PathBase
der App ersetzt. Wenn Sie in der App einen Endpunkt angeben, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Den Client an einen anderen Endpunkt umleiten, in der Regel in Fällen, in denen eine andere App den Fehler verarbeitet. Für Web-Apps gibt die Adressleiste des Browsers des Clients den umgeleiteten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der anfänglichen Umleitungsantwort nicht beibehalten und zurückgeben.
UseStatusCodePagesWithReExecute
Die Erweiterungsmethode UseStatusCodePagesWithReExecute:
- Generiert den Antworttext durch die erneute Ausführung der Anforderungspipeline mithilfe eines alternativen Pfads.
- Ändert den Statuscode nicht vor oder nach der erneuten Ausführung der Pipeline.
Die neue Pipelineausführung kann den Statuscode der Antwort ändern, da sie die vollständige Kontrolle über den Statuscode hat. Wenn die neue Pipeline den Statuscode nicht ändert, wird der ursprüngliche Statuscode an den Client gesendet.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Wenn in der App ein Endpunkt angegeben ist, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Die Anforderung ohne Umleitung an einen anderen Endpunkt verarbeiten. Für Web-Apps gibt die Adressleiste des Browsers des Clients den ursprünglich angeforderten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der Antwort beibehalten und zurückgeben.
Die URL-Vorlage muss mit /
beginnen und kann den Platzhalter {0}
für den Statuscode enthalten. Um den Statuscode als Abfragezeichenfolgenparameter zu übergeben, übergeben Sie ein zweites Argument an UseStatusCodePagesWithReExecute
. Beispiel:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Der Endpunkt, der den Fehler verarbeitet, kann die ursprüngliche URL abrufen, die den Fehler generiert hat (siehe folgendes Beispiel):
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = $"{statusCodeReExecuteFeature.OriginalPathBase}"
+ $"{statusCodeReExecuteFeature.OriginalPath}"
+ $"{statusCodeReExecuteFeature.OriginalQueryString}";
}
}
}
Da diese Middleware die Anforderungspipeline erneut ausführen kann, gilt Folgendes:
- Middlewares müssen die erneute Ausführung mit derselben Anforderung verarbeiten. Dies bedeutet normalerweise, dass ihr Zustand nach dem Aufrufen von
_next
bereinigt oder die Verarbeitung imHttpContext
zwischengespeichert wird, um eine Wiederholung zu vermeiden. Bei der Verarbeitung des Anforderungstexts bedeutet dies, dass Ergebnisse wie beispielsweise der Formularleser entweder gepuffert oder zwischengespeichert werden. - Bereichsbezogene Dienste bleiben gleich.
Deaktivieren von Statuscodeseiten
Verwenden Sie das Attribut [SkipStatusCodePages], um Statuscodeseiten für einen MVC-Controller oder eine MVC-Aktionsmethode zu deaktivieren.
Verwenden Sie IStatusCodePagesFeature, um Statuscodeseiten für bestimmte Anforderungen in der Handlermethode von Razor Pages oder in einem MVC-Controller zu deaktivieren:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Ausnahmebehandlungscode
Code auf Seiten zur Ausnahmebehandlung kann ebenfalls Ausnahmen auslösen. Produktionsfehlerseiten sollten gründlich getestet werden. Achten Sie darauf, dabei keine eigenen Ausnahmen auszulösen.
Antwortheader
Nachdem die Header für eine Antwort gesendet wurden:
- Die App kann den Statuscode der Antwort nicht ändern.
- Weder Ausnahmeseiten noch Handler können ausgeführt werden. Die Antwort muss abgeschlossen oder die Verbindung unterbrochen werden.
Sichere Ausnahmebehandlung
Neben der Ausnahmebehandlungslogik in einer App kann die HTTP-Serverimplementierung einige Ausnahmebehandlungen durchführen. Wenn der Server eine Ausnahme erfasst, bevor die Antwortheader gesendet werden, sendet der Server die Antwort 500 - Internal Server Error
ohne Antworttext. Wenn der Server eine Ausnahme auffängt, nachdem die Antwortheader gesendet wurden, schließt der Server die Verbindung. Anforderungen, die nicht von der App verarbeitet werden, werden vom Server verarbeitet. Jede Ausnahme, die bei der Anforderungsverarbeitung durch den Server auftritt, wird durch die Ausnahmebehandlung des Servers verarbeitet. Die benutzerdefinierten Fehlerseiten der App, Middleware zur Fehlerbehandlung und Filter haben keine Auswirkungen auf dieses Verhalten.
Fehlerbehandlung während des Starts
Nur auf Hostebene können Ausnahmen behandelt werden, die während des Starts einer App auftreten. Der Host kann für das Erfassen von Startfehlern und Erfassen detaillierter Fehler konfiguriert werden.
Die Hostingebene kann nur dann für einen beim Start erfassten Fehler eine Fehlerseite anzeigen, wenn der Fehler nach der Bindung an die Hostadresse bzw. den Port auftritt. Wenn die Bindung misslingt:
- Die Hostebene protokolliert eine kritische Ausnahme.
- Der DotNet-Prozess stürzt ab.
- Wenn der HTTP-Server Kestrel heißt, wird keine Fehlerseite angezeigt.
Wenn sie auf IIS (oder Azure App Service) oder IIS Express ausgeführt wird, wird ein Prozessfehler 502.5 vom ASP.NET Core-Modul zurückgegeben, wenn der Prozess nicht starten kann. Weitere Informationen finden Sie unter Problembehandlung bei ASP.NET Core in Azure App Service und IIS.
Datenbank-Fehlerseite
Der Ausnahmefilter der Datenbankentwicklerseite AddDatabaseDeveloperPageExceptionFilter erfasst datenbankbezogene Ausnahmen, die mithilfe von Entity Framework Core-Migrationen aufgelöst werden können. Wenn diese Ausnahmen auftreten, wird eine HTML-Antwort mit Details zu möglichen Aktionen zum Beheben des Problems generiert. Diese Seite ist nur in der Entwicklungsumgebung aktiviert. Der folgende Code fügt den Ausnahmefilter der Datenbankentwicklerseite hinzu:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Ausnahmefilter
In MVC-Apps können Ausnahmefilter global oder auf einen Controller oder eine Aktion bezogen konfiguriert werden. In Razor Pages-Apps können sie global oder auf ein Seitenmodell bezogen konfiguriert werden. Diese Filter verarbeiten jede nicht behandelte Ausnahme, die während der Ausführung eine Controlleraktion oder eines anderen Filters auftritt. Weitere Informationen finden Sie unter Filter in ASP.NET Core.
Ausnahmefilter eignen sich zum Auffangen von Ausnahmen, die in MVC-Aktionen ausgelöst werden. Sie sind jedoch nicht so flexibel wie die integrierte Middleware für die Ausnahmebehandlung, UseExceptionHandler. Es wird empfohlen, UseExceptionHandler
zu verwenden, wenn Sie für die Fehlerbehandlung auf Grundlage einer ausgewählten MVC-Aktion eine andere Strategie auswählen müssen.
Modellstatusfehler
Informationen zum Behandeln von Modellstatusfehlern finden Sie unter Modellbindung und Modellvalidierung.
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
):
- ExceptionHandlerMiddleware generiert eine Problemdetailantwort, wenn kein benutzerdefinierter Handler definiert ist.
- StatusCodePagesMiddleware generiert standardmäßig eine Problemdetailantwort.
- DeveloperExceptionPageMiddleware generiert eine Problemdetailantwort während der Entwicklungsphase, wenn der
Accept
-HTTP-Anforderungsheader nichttext/html
enthält.
Mit dem folgenden Code wird die App so konfiguriert, dass eine Problemdetailantwort für alle Fehlerantworten von HTTP-Client und -Server generiert wird, die noch keinen Textinhalt aufweisen:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Im nächsten Abschnitt wird gezeigt, wie Sie den Antworttext mit den Problemdetails anpassen.
Anpassen von Problemdetails
Die automatische Erstellung von ProblemDetails
kann mit einer der folgenden Optionen angepasst werden:
- Verwenden Sie
ProblemDetailsOptions.CustomizeProblemDetails
- Verwenden einer benutzerdefinierten
IProblemDetailsWriter
-Datei - Aufrufen von
IProblemDetailsService
in einer Middleware
CustomizeProblemDetails
Vorgang
Die generierten Problemdetails können mithilfe von CustomizeProblemDetails angepasst werden, und die Anpassungen werden auf alle automatisch generierten Problemdetails angewandt.
Der folgende Code verwendet ProblemDetailsOptions, um CustomizeProblemDetails festzulegen:
builder.Services.AddProblemDetails(options =>
options.CustomizeProblemDetails = ctx =>
ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Beispielsweise erzeugt ein HTTP Status 400 Bad Request
-Endpunkt den folgenden Antworttext mit Problemdetails:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Benutzerdefinierter IProblemDetailsWriter
Eine IProblemDetailsWriter-Implementierung kann für erweiterte Anpassungen erstellt werden.
public class SampleProblemDetailsWriter : IProblemDetailsWriter
{
// Indicates that only responses with StatusCode == 400
// are handled by this writer. All others are
// handled by different registered writers if available.
public bool CanWrite(ProblemDetailsContext context)
=> context.HttpContext.Response.StatusCode == 400;
public ValueTask WriteAsync(ProblemDetailsContext context)
{
// Additional customizations.
// Write to the response.
var response = context.HttpContext.Response;
return new ValueTask(response.WriteAsJsonAsync(context.ProblemDetails));
}
}
Hinweis: Wenn Sie einen benutzerdefinierten IProblemDetailsWriter
verwenden, muss der benutzerdefinierte IProblemDetailsWriter
vor dem Aufrufen von AddRazorPages, AddControllers, AddControllersWithViews oder AddMvc registriert werden:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTransient<IProblemDetailsWriter, SampleProblemDetailsWriter>();
var app = builder.Build();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsWriter>() is
{ } problemDetailsService)
{
if (problemDetailsService.CanWrite(new ProblemDetailsContext() { HttpContext = context }))
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.Run();
Problemdetails von Middleware
Ein alternativer Ansatz zur Verwendung von ProblemDetailsOptions mit CustomizeProblemDetails ist das Festlegen von ProblemDetails in Middleware. Eine Problemdetailantwort kann durch Aufrufen von IProblemDetailsService.WriteAsync
geschrieben werden:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStatusCodePages();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.DivisionByZeroError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.NegativeRadicandError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.MapControllers();
app.Run();
Im obigen Code geben die Minimal-API-Endpunkte /divide
und /squareroot
bei einer Fehlereingabe die erwartete benutzerdefinierte Problemantwort zurück.
Die API-Controllerendpunkte geben bei einer Fehlereingabe die Standardproblemantwort zurück, nicht die benutzerdefinierte Problemantwort. Die Standardproblemantwort wird zurückgegeben, da der API-Controller in den Antwortdatenstrom (Problemdetails für Fehlerstatuscodes) geschrieben hat, bevor IProblemDetailsService.WriteAsync
aufgerufen wird, und die Antwort nicht erneut geschrieben wird.
Der folgende ValuesController
gibt BadRequestResult zurück, das in den Antwortdatenstrom geschrieben wird. Damit wird verhindert, dass die benutzerdefinierte Problemantwort zurückgegeben wird.
[Route("api/[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
// /api/values/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Numerator / Denominator);
}
// /api/values/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Math.Sqrt(radicand));
}
}
Der folgende Values3Controller
gibt ControllerBase.Problem
zurück, sodass das erwartete Ergebnis für das benutzerdefinierte Problem zurückgegeben wird:
[Route("api/[controller]/[action]")]
[ApiController]
public class Values3Controller : ControllerBase
{
// /api/values3/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Divison by zero is not defined.",
type: "https://en.wikipedia.org/wiki/Division_by_zero",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Numerator / Denominator);
}
// /api/values3/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Negative or complex numbers are not valid input.",
type: "https://en.wikipedia.org/wiki/Square_root",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Math.Sqrt(radicand));
}
}
Erstellen von ProblemDetails-Nutzdaten für Ausnahmen
Betrachten Sie die folgende App:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapControllers();
app.Run();
Wenn in Nicht-Entwicklungsumgebungen eine Ausnahme auftritt, wird die folgende standardmäßige ProblemDetails-Antwort an den Client zurückgegeben:
{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500,"traceId":"00-b644<snip>-00"
}
Für die meisten Apps ist für Ausnahmen nur der oben stehende Code erforderlich. Der folgende Abschnitt zeigt jedoch, wie Sie detailliertere Problemantworten erhalten.
Eine Alternative zu einer benutzerdefinierten Ausnahmebehandlungsseite ist das Angeben eines Lambda-Ausdrucks für UseExceptionHandler. Die Verwendung einer Lambdafunktion ermöglicht den Zugriff auf den Fehler und das Schreiben einer Problemdetailantwort mit IProblemDetailsService.WriteAsync
:
using Microsoft.AspNetCore.Diagnostics;
using static System.Net.Mime.MediaTypeNames;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = Text.Plain;
var title = "Bad Input";
var detail = "Invalid input";
var type = "https://errors.example.com/badInput";
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
var exceptionHandlerFeature =
context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType != null &&
exceptionType.Message.Contains("infinity"))
{
title = "Argument exception";
detail = "Invalid input";
type = "https://errors.example.com/argumentException";
}
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = title,
Detail = detail,
Type = type
}
});
}
});
});
}
app.MapControllers();
app.Run();
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
Ein alternativer Ansatz zum Generieren von Problemdetails besteht darin, das Drittanbieter-NuGet-Paket Hellang.Middleware.ProblemDetails zu verwenden, mit dem Ausnahmen und Clientfehler zu Problemdetails zugeordnet werden können.
Zusätzliche Ressourcen
- Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)
- Problembehandlung bei ASP.NET Core in Azure App Service und IIS
- Problembehandlung für häufige Fehler bei Azure App Service und IIS mit ASP.NET Core
- Behandeln von Fehlern in ASP.NET Core-controllerbasierten Web-APIs
- Behandeln von Fehlern in Minimal-API-Apps
Von Tom Dykstra
Dieser Artikel beschreibt grundsätzliche Vorgehensweisen zur Behandlung von Fehlern in ASP.NET Core-Web-Apps. Weitere Informationen finden Sie auch unter Fehlerbehandlung in ASP.NET Core-Web-APIs und Behandeln von Fehlern in Minimal-API-Apps.
Seite mit Ausnahmen für Entwickler
Die Seite mit Ausnahmen für Entwickler enthält ausführliche Informationen zu unbehandelten Anforderungsausnahmen. ASP.NET Core-Apps aktivieren standardmäßig die Seite mit Ausnahmen für Entwickler, wenn die folgenden Aussagen beide zutreffen:
- Die Ausführung erfolgt in der Entwicklungsumgebung.
- Die App wird mit den aktuellen Vorlagen erstellt, also mit WebApplication.CreateBuilder. Apps, die mithilfe von
WebHost.CreateDefaultBuilder
erstellt wurden, müssen die Seite mit den Ausnahmeseite für Entwickler durch Aufrufen vonapp.UseDeveloperExceptionPage
inConfigure
aktivieren.
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.
Bei Ausführung der App in der Produktionsumgebung dürfen keine detaillierten Informationen zu den Ausnahmen öffentlich angezeigt werden. 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
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.
Seite „Ausnahmehandler“
Um eine benutzerdefinierte Fehlerbehandlungsseite für die Produktionsumgebung zu konfigurieren, rufen Sie UseExceptionHandler auf. Die Aufgaben der Middleware zur Ausnahmebehandlung:
- Dient zum Abfangen und Protokollieren unbehandelter Ausnahmen.
- Führt erneut die Anforderung in einer anderen Pipeline im angegebenen Pfad aus. Die Anforderung wird nicht erneut ausgeführt, wenn die Antwort gestartet wurde. Der von der Vorlage generierte Code führt die Anforderung erneut mit dem
/Error
-Pfad aus.
Warnung
Wenn die alternative Pipeline eigenständig eine Ausnahme auslöst, löst die Middleware für die Ausnahmebehandlung erneut die ursprüngliche Ausnahme aus.
Da diese Middleware die Anforderungspipeline erneut ausführen kann, gilt Folgendes:
- Middlewares müssen die erneute Ausführung mit derselben Anforderung verarbeiten. Dies bedeutet normalerweise, dass ihr Zustand nach dem Aufrufen von
_next
bereinigt oder die Verarbeitung imHttpContext
zwischengespeichert wird, um eine Wiederholung zu vermeiden. Bei der Verarbeitung des Anforderungstexts bedeutet dies, dass Ergebnisse wie beispielsweise der Formularleser entweder gepuffert oder zwischengespeichert werden. - Für die UseExceptionHandler(IApplicationBuilder, String)-Überladung, die in Vorlagen verwendet wird, wird nur der Anforderungspfad geändert, und die Routendaten werden gelöscht. Anforderungsdaten wie Header, Methoden und Elemente werden unverändert wiederverwendet.
- Bereichsbezogene Dienste bleiben gleich.
Im folgenden Beispiel fügt UseExceptionHandler die Middleware zur Ausnahmebehandlung in Nichtentwicklungsumgebungen hinzu:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Die Razor Pages-App-Vorlage stellt im Ordner Pages eine Fehlerseite (.cshtml
) und eine PageModel-Klasse (ErrorModel
) bereit. Die Projektvorlage für eine MVC-App enthält eine Error
-Aktionsmethode und eine Fehleransicht für den Home-Controller.
Die Middleware für die Ausnahmebehandlung führt die Anforderung unter Verwendung der ursprünglichen HTTP-Methode erneut aus. Wenn ein Endpunkt für die Fehlerbehandlung auf bestimmte HTTP-Methoden beschränkt ist, wird er nur für diese Methoden ausgeführt. Beispielsweise wird eine MVC-Controller-Aktion, die das Attribut [HttpGet]
verwendet, nur für GET-Anforderungen ausgeführt. Um sicherzustellen, dass alle Anforderungen die benutzerdefinierte Seite für die Fehlerbehandlung erreichen, beschränken Sie die Endpunkte nicht auf bestimmte HTTP-Methoden.
So behandeln Sie Ausnahmen unterschiedlich, basierend auf der ursprünglichen HTTP-Methode:
- Für Razor Pages erstellen Sie mehrere Handlermethoden. Verwenden Sie beispielsweise
OnGet
zum Behandeln von GET-Ausnahmen undOnPost
zum Behandeln von POST-Ausnahmen. - Für MVC wenden Sie HTTP-Verbattribute auf mehrere Aktionen an. Verwenden Sie beispielsweise
[HttpGet]
zum Behandeln von GET-Ausnahmen und[HttpPost]
zum Behandeln von POST-Ausnahmen.
Um nicht authentifizierten Benutzern die Anzeige der benutzerdefinierten Seite für die Fehlerbehandlung zu ermöglichen, stellen Sie sicher, dass der anonyme Zugriff unterstützt wird.
Zugreifen auf die Ausnahme
Verwenden Sie IExceptionHandlerPathFeature, um auf die Ausnahme oder den Pfad der ursprünglichen Anforderung in einem Fehlerhandler zuzugreifen. Im folgenden Beispiel wird IExceptionHandlerPathFeature
verwendet, um weitere Informationen zur ausgelösten Ausnahme zu erhalten:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "The file was not found.";
}
if (exceptionHandlerPathFeature?.Path == "/")
{
ExceptionMessage ??= string.Empty;
ExceptionMessage += " Page: Home.";
}
}
}
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
Lambda-Ausdruck für Ausnahmehandler
Eine Alternative zu einer benutzerdefinierten Ausnahmebehandlungsseite ist das Angeben eines Lambda-Ausdrucks für UseExceptionHandler. Die Verwendung eines Lambda-Ausdrucks ermöglicht den Zugriff auf den Fehler, bevor die Antwort zurückgegeben wird.
Der folgende Code verwendet einen Lambdaausdruck für die Ausnahmebehandlung:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
UseStatusCodePages
Die ASP.NET Core-App stellt für HTTP-Fehlerstatuscodes wie 404 – Nicht gefunden standardmäßig keine Statuscodeseite zur Verfügung. Wenn die App einen HTTP-Fehlerstatuscode im Bereich 400 bis 599 ohne Text festlegt, werden der Statuscode und ein leerer Antworttext zurückgegeben. Um für gängige Statuscodes einfache Handler im Textformat zu aktivieren, rufen Sie UseStatusCodePages in Program.cs
auf:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Rufen Sie UseStatusCodePages
vor der Middleware für die Anforderungsverarbeitung auf. Rufen Sie beispielsweise UseStatusCodePages
vor der Middleware für statische Dateien und der Middleware für Endpunkte auf.
Wenn UseStatusCodePages
nicht verwendet wird, wird beim Navigieren zu einer URL ohne Endpunkt eine browserabhängige Fehlermeldung zurückgegeben, die angibt, dass der Endpunkt nicht gefunden werden kann. Wenn UseStatusCodePages
aufgerufen wird, gibt der Browser die folgende Antwort zurück:
Status Code: 404; Not Found
UseStatusCodePages
wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
Hinweis
Die Middleware für Statuscodeseiten erfasst keine Ausnahmen. Um eine benutzerdefinierte Fehlerbehandlungsseite bereitzustellen, verwenden Sie die Ausnahmehandlerseite.
UseStatusCodePages mit Formatzeichenfolge
Um den Inhaltstyp und Text der Antwort anzupassen, verwenden Sie die Überladung von UseStatusCodePages, die einen Inhaltstyp und eine Formatierungszeichenfolge erfordert:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// using static System.Net.Mime.MediaTypeNames;
app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");
Im vorangehenden Code ist {0}
ein Platzhalter für den Fehlercode.
UseStatusCodePages
mit Formatzeichenfolge wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
UseStatusCodePages mit Lambda-Ausdruck
Um benutzerdefinierten Code für die Fehlerbehandlung und das Schreiben von Antworten anzugeben, verwenden Sie die Überladung von UseStatusCodePages, die einen Lambda-Ausdruck verwendet:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async statusCodeContext =>
{
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
$"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});
UseStatusCodePages
mit Lambdaausdruck wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
UseStatusCodePagesWithRedirects
Die Erweiterungsmethode UseStatusCodePagesWithRedirects:
- Sendet den Statuscode 302 Found (Gefunden) an den Client.
- Leitet den Client an den in der URL-Vorlage angegebenen Fehlerbehandlungsendpunkt weiter. Der Fehlerbehandlungsendpunkt zeigt in der Regel Fehlerinformationen an und gibt den HTTP-Code 200 zurück.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Die URL-Vorlage kann, wie im vorangehenden Code gezeigt, einen {0}
-Platzhalter für den Statuscode enthalten. Wenn die URL-Vorlage mit einer Tilde (~
) beginnt, wird ~
durch die Angabe für PathBase
der App ersetzt. Wenn Sie in der App einen Endpunkt angeben, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Den Client an einen anderen Endpunkt umleiten, in der Regel in Fällen, in denen eine andere App den Fehler verarbeitet. Für Web-Apps gibt die Adressleiste des Browsers des Clients den umgeleiteten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der anfänglichen Umleitungsantwort nicht beibehalten und zurückgeben.
UseStatusCodePagesWithReExecute
Die Erweiterungsmethode UseStatusCodePagesWithReExecute:
- Generiert den Antworttext durch die erneute Ausführung der Anforderungspipeline mithilfe eines alternativen Pfads.
- Ändert den Statuscode nicht vor oder nach der erneuten Ausführung der Pipeline.
Die neue Pipelineausführung kann den Statuscode der Antwort ändern, da sie die vollständige Kontrolle über den Statuscode hat. Wenn die neue Pipeline den Statuscode nicht ändert, wird der ursprüngliche Statuscode an den Client gesendet.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Wenn in der App ein Endpunkt angegeben ist, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Die Anforderung ohne Umleitung an einen anderen Endpunkt verarbeiten. Für Web-Apps gibt die Adressleiste des Browsers des Clients den ursprünglich angeforderten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der Antwort beibehalten und zurückgeben.
Die URL-Vorlage muss mit /
beginnen und kann den Platzhalter {0}
für den Statuscode enthalten. Um den Statuscode als Abfragezeichenfolgenparameter zu übergeben, übergeben Sie ein zweites Argument an UseStatusCodePagesWithReExecute
. Beispiel:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Der Endpunkt, der den Fehler verarbeitet, kann die ursprüngliche URL abrufen, die den Fehler generiert hat (siehe folgendes Beispiel):
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = $"{statusCodeReExecuteFeature.OriginalPathBase}"
+ $"{statusCodeReExecuteFeature.OriginalPath}"
+ $"{statusCodeReExecuteFeature.OriginalQueryString}";
}
}
}
Da diese Middleware die Anforderungspipeline erneut ausführen kann, gilt Folgendes:
- Middlewares müssen die erneute Ausführung mit derselben Anforderung verarbeiten. Dies bedeutet normalerweise, dass ihr Zustand nach dem Aufrufen von
_next
bereinigt oder die Verarbeitung imHttpContext
zwischengespeichert wird, um eine Wiederholung zu vermeiden. Bei der Verarbeitung des Anforderungstexts bedeutet dies, dass Ergebnisse wie beispielsweise der Formularleser entweder gepuffert oder zwischengespeichert werden. - Bereichsbezogene Dienste bleiben gleich.
Deaktivieren von Statuscodeseiten
Verwenden Sie das Attribut [SkipStatusCodePages], um Statuscodeseiten für einen MVC-Controller oder eine MVC-Aktionsmethode zu deaktivieren.
Verwenden Sie IStatusCodePagesFeature, um Statuscodeseiten für bestimmte Anforderungen in der Handlermethode von Razor Pages oder in einem MVC-Controller zu deaktivieren:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Ausnahmebehandlungscode
Code auf Seiten zur Ausnahmebehandlung kann ebenfalls Ausnahmen auslösen. Produktionsfehlerseiten sollten gründlich getestet werden. Achten Sie darauf, dabei keine eigenen Ausnahmen auszulösen.
Antwortheader
Nachdem die Header für eine Antwort gesendet wurden:
- Die App kann den Statuscode der Antwort nicht ändern.
- Weder Ausnahmeseiten noch Handler können ausgeführt werden. Die Antwort muss abgeschlossen oder die Verbindung unterbrochen werden.
Sichere Ausnahmebehandlung
Neben der Ausnahmebehandlungslogik in einer App kann die HTTP-Serverimplementierung einige Ausnahmebehandlungen durchführen. Wenn der Server eine Ausnahme erfasst, bevor die Antwortheader gesendet werden, sendet der Server die Antwort 500 - Internal Server Error
ohne Antworttext. Wenn der Server eine Ausnahme auffängt, nachdem die Antwortheader gesendet wurden, schließt der Server die Verbindung. Anforderungen, die nicht von der App verarbeitet werden, werden vom Server verarbeitet. Jede Ausnahme, die bei der Anforderungsverarbeitung durch den Server auftritt, wird durch die Ausnahmebehandlung des Servers verarbeitet. Die benutzerdefinierten Fehlerseiten der App, Middleware zur Fehlerbehandlung und Filter haben keine Auswirkungen auf dieses Verhalten.
Fehlerbehandlung während des Starts
Nur auf Hostebene können Ausnahmen behandelt werden, die während des Starts einer App auftreten. Der Host kann für das Erfassen von Startfehlern und Erfassen detaillierter Fehler konfiguriert werden.
Die Hostingebene kann nur dann für einen beim Start erfassten Fehler eine Fehlerseite anzeigen, wenn der Fehler nach der Bindung an die Hostadresse bzw. den Port auftritt. Wenn die Bindung misslingt:
- Die Hostebene protokolliert eine kritische Ausnahme.
- Der DotNet-Prozess stürzt ab.
- Wenn der HTTP-Server Kestrel heißt, wird keine Fehlerseite angezeigt.
Wenn sie auf IIS (oder Azure App Service) oder IIS Express ausgeführt wird, wird ein Prozessfehler 502.5 vom ASP.NET Core-Modul zurückgegeben, wenn der Prozess nicht starten kann. Weitere Informationen finden Sie unter Problembehandlung bei ASP.NET Core in Azure App Service und IIS.
Datenbank-Fehlerseite
Der Ausnahmefilter der Datenbankentwicklerseite AddDatabaseDeveloperPageExceptionFilter erfasst datenbankbezogene Ausnahmen, die mithilfe von Entity Framework Core-Migrationen aufgelöst werden können. Wenn diese Ausnahmen auftreten, wird eine HTML-Antwort mit Details zu möglichen Aktionen zum Beheben des Problems generiert. Diese Seite ist nur in der Entwicklungsumgebung aktiviert. Der folgende Code fügt den Ausnahmefilter der Datenbankentwicklerseite hinzu:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Ausnahmefilter
In MVC-Apps können Ausnahmefilter global oder auf einen Controller oder eine Aktion bezogen konfiguriert werden. In Razor Pages-Apps können sie global oder auf ein Seitenmodell bezogen konfiguriert werden. Diese Filter verarbeiten jede nicht behandelte Ausnahme, die während der Ausführung eine Controlleraktion oder eines anderen Filters auftritt. Weitere Informationen finden Sie unter Filter in ASP.NET Core.
Ausnahmefilter eignen sich zum Auffangen von Ausnahmen, die in MVC-Aktionen ausgelöst werden. Sie sind jedoch nicht so flexibel wie die integrierte Middleware für die Ausnahmebehandlung, UseExceptionHandler. Es wird empfohlen, UseExceptionHandler
zu verwenden, wenn Sie für die Fehlerbehandlung auf Grundlage einer ausgewählten MVC-Aktion eine andere Strategie auswählen müssen.
Modellstatusfehler
Informationen zum Behandeln von Modellstatusfehlern finden Sie unter Modellbindung und Modellvalidierung.
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
):
- ExceptionHandlerMiddleware generiert eine Problemdetailantwort, wenn kein benutzerdefinierter Handler definiert ist.
- StatusCodePagesMiddleware generiert standardmäßig eine Problemdetailantwort.
- DeveloperExceptionPageMiddleware generiert eine Problemdetailantwort während der Entwicklungsphase, wenn der
Accept
-HTTP-Anforderungsheader nichttext/html
enthält.
Mit dem folgenden Code wird die App so konfiguriert, dass eine Problemdetailantwort für alle Fehlerantworten von HTTP-Client und -Server generiert wird, die noch keinen Textinhalt aufweisen:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Im nächsten Abschnitt wird gezeigt, wie Sie den Antworttext mit den Problemdetails anpassen.
Anpassen von Problemdetails
Die automatische Erstellung von ProblemDetails
kann mit einer der folgenden Optionen angepasst werden:
- Verwenden Sie
ProblemDetailsOptions.CustomizeProblemDetails
- Verwenden einer benutzerdefinierten
IProblemDetailsWriter
-Datei - Aufrufen von
IProblemDetailsService
in einer Middleware
CustomizeProblemDetails
Vorgang
Die generierten Problemdetails können mithilfe von CustomizeProblemDetails angepasst werden, und die Anpassungen werden auf alle automatisch generierten Problemdetails angewandt.
Der folgende Code verwendet ProblemDetailsOptions, um CustomizeProblemDetails festzulegen:
builder.Services.AddProblemDetails(options =>
options.CustomizeProblemDetails = ctx =>
ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
Beispielsweise erzeugt ein HTTP Status 400 Bad Request
-Endpunkt den folgenden Antworttext mit Problemdetails:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Benutzerdefinierter IProblemDetailsWriter
Eine IProblemDetailsWriter-Implementierung kann für erweiterte Anpassungen erstellt werden.
public class SampleProblemDetailsWriter : IProblemDetailsWriter
{
// Indicates that only responses with StatusCode == 400
// are handled by this writer. All others are
// handled by different registered writers if available.
public bool CanWrite(ProblemDetailsContext context)
=> context.HttpContext.Response.StatusCode == 400;
public ValueTask WriteAsync(ProblemDetailsContext context)
{
// Additional customizations.
// Write to the response.
var response = context.HttpContext.Response;
return new ValueTask(response.WriteAsJsonAsync(context.ProblemDetails));
}
}
Hinweis: Wenn Sie einen benutzerdefinierten IProblemDetailsWriter
verwenden, muss der benutzerdefinierte IProblemDetailsWriter
vor dem Aufrufen von AddRazorPages, AddControllers, AddControllersWithViews oder AddMvc registriert werden:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTransient<IProblemDetailsWriter, SampleProblemDetailsWriter>();
var app = builder.Build();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsWriter>() is
{ } problemDetailsService)
{
if (problemDetailsService.CanWrite(new ProblemDetailsContext() { HttpContext = context }))
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.Run();
Problemdetails von Middleware
Ein alternativer Ansatz zur Verwendung von ProblemDetailsOptions mit CustomizeProblemDetails ist das Festlegen von ProblemDetails in Middleware. Eine Problemdetailantwort kann durch Aufrufen von IProblemDetailsService.WriteAsync
geschrieben werden:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStatusCodePages();
// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
await next(context);
var mathErrorFeature = context.Features.Get<MathErrorFeature>();
if (mathErrorFeature is not null)
{
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
(string Detail, string Type) details = mathErrorFeature.MathError switch
{
MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
"https://en.wikipedia.org/wiki/Division_by_zero"),
_ => ("Negative or complex numbers are not valid input.",
"https://en.wikipedia.org/wiki/Square_root")
};
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = "Bad Input",
Detail = details.Detail,
Type = details.Type
}
});
}
}
});
// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
if (denominator == 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.DivisionByZeroError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(numerator / denominator);
});
// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
if (radicand < 0)
{
var errorType = new MathErrorFeature { MathError =
MathErrorType.NegativeRadicandError };
context.Features.Set(errorType);
return Results.BadRequest();
}
return Results.Ok(Math.Sqrt(radicand));
});
app.MapControllers();
app.Run();
Im obigen Code geben die Minimal-API-Endpunkte /divide
und /squareroot
bei einer Fehlereingabe die erwartete benutzerdefinierte Problemantwort zurück.
Die API-Controllerendpunkte geben bei einer Fehlereingabe die Standardproblemantwort zurück, nicht die benutzerdefinierte Problemantwort. Die Standardproblemantwort wird zurückgegeben, da der API-Controller in den Antwortdatenstrom (Problemdetails für Fehlerstatuscodes) geschrieben hat, bevor IProblemDetailsService.WriteAsync
aufgerufen wird, und die Antwort nicht erneut geschrieben wird.
Der folgende ValuesController
gibt BadRequestResult zurück, das in den Antwortdatenstrom geschrieben wird. Damit wird verhindert, dass die benutzerdefinierte Problemantwort zurückgegeben wird.
[Route("api/[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
// /api/values/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Numerator / Denominator);
}
// /api/values/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return BadRequest();
}
return Ok(Math.Sqrt(radicand));
}
}
Der folgende Values3Controller
gibt ControllerBase.Problem
zurück, sodass das erwartete Ergebnis für das benutzerdefinierte Problem zurückgegeben wird:
[Route("api/[controller]/[action]")]
[ApiController]
public class Values3Controller : ControllerBase
{
// /api/values3/divide/1/2
[HttpGet("{Numerator}/{Denominator}")]
public IActionResult Divide(double Numerator, double Denominator)
{
if (Denominator == 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.DivisionByZeroError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Divison by zero is not defined.",
type: "https://en.wikipedia.org/wiki/Division_by_zero",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Numerator / Denominator);
}
// /api/values3/squareroot/4
[HttpGet("{radicand}")]
public IActionResult Squareroot(double radicand)
{
if (radicand < 0)
{
var errorType = new MathErrorFeature
{
MathError = MathErrorType.NegativeRadicandError
};
HttpContext.Features.Set(errorType);
return Problem(
title: "Bad Input",
detail: "Negative or complex numbers are not valid input.",
type: "https://en.wikipedia.org/wiki/Square_root",
statusCode: StatusCodes.Status400BadRequest
);
}
return Ok(Math.Sqrt(radicand));
}
}
Erstellen von ProblemDetails-Nutzdaten für Ausnahmen
Betrachten Sie die folgende App:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapControllers();
app.Run();
Wenn in Nicht-Entwicklungsumgebungen eine Ausnahme auftritt, wird die folgende standardmäßige ProblemDetails-Antwort an den Client zurückgegeben:
{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500,"traceId":"00-b644<snip>-00"
}
Für die meisten Apps ist für Ausnahmen nur der oben stehende Code erforderlich. Der folgende Abschnitt zeigt jedoch, wie Sie detailliertere Problemantworten erhalten.
Eine Alternative zu einer benutzerdefinierten Ausnahmebehandlungsseite ist das Angeben eines Lambda-Ausdrucks für UseExceptionHandler. Die Verwendung einer Lambdafunktion ermöglicht den Zugriff auf den Fehler und das Schreiben einer Problemdetailantwort mit IProblemDetailsService.WriteAsync
:
using Microsoft.AspNetCore.Diagnostics;
using static System.Net.Mime.MediaTypeNames;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = Text.Plain;
var title = "Bad Input";
var detail = "Invalid input";
var type = "https://errors.example.com/badInput";
if (context.RequestServices.GetService<IProblemDetailsService>() is
{ } problemDetailsService)
{
var exceptionHandlerFeature =
context.Features.Get<IExceptionHandlerFeature>();
var exceptionType = exceptionHandlerFeature?.Error;
if (exceptionType != null &&
exceptionType.Message.Contains("infinity"))
{
title = "Argument exception";
detail = "Invalid input";
type = "https://errors.example.com/argumentException";
}
await problemDetailsService.WriteAsync(new ProblemDetailsContext
{
HttpContext = context,
ProblemDetails =
{
Title = title,
Detail = detail,
Type = type
}
});
}
});
});
}
app.MapControllers();
app.Run();
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
Ein alternativer Ansatz zum Generieren von Problemdetails besteht darin, das Drittanbieter-NuGet-Paket Hellang.Middleware.ProblemDetails zu verwenden, mit dem Ausnahmen und Clientfehler zu Problemdetails zugeordnet werden können.
Zusätzliche Ressourcen
Von Tom Dykstra
Dieser Artikel beschreibt grundsätzliche Vorgehensweisen zur Behandlung von Fehlern in ASP.NET Core-Web-Apps. Weitere Informationen zu Web-APIs finden Sie unter Behandeln von Fehlern in ASP.NET Core-controllerbasierten Web-APIs.
Seite mit Ausnahmen für Entwickler
Die Seite mit Ausnahmen für Entwickler enthält ausführliche Informationen zu unbehandelten Anforderungsausnahmen. ASP.NET Core-Apps aktivieren standardmäßig die Seite mit Ausnahmen für Entwickler, wenn die folgenden Aussagen beide zutreffen:
- Die Ausführung erfolgt in der Entwicklungsumgebung.
- Die App wird mit den aktuellen Vorlagen erstellt, also mit WebApplication.CreateBuilder. Apps, die mithilfe von
WebHost.CreateDefaultBuilder
erstellt wurden, müssen die Seite mit den Ausnahmeseite für Entwickler durch Aufrufen vonapp.UseDeveloperExceptionPage
inConfigure
aktivieren.
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.
Bei Ausführung der App in der Produktionsumgebung dürfen keine detaillierten Informationen zu den Ausnahmen öffentlich angezeigt werden. 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
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.
Seite „Ausnahmehandler“
Um eine benutzerdefinierte Fehlerbehandlungsseite für die Produktionsumgebung zu konfigurieren, rufen Sie UseExceptionHandler auf. Die Aufgaben der Middleware zur Ausnahmebehandlung:
- Dient zum Abfangen und Protokollieren unbehandelter Ausnahmen.
- Führt erneut die Anforderung in einer anderen Pipeline im angegebenen Pfad aus. Die Anforderung wird nicht erneut ausgeführt, wenn die Antwort gestartet wurde. Der von der Vorlage generierte Code führt die Anforderung erneut mit dem
/Error
-Pfad aus.
Warnung
Wenn die alternative Pipeline eigenständig eine Ausnahme auslöst, löst die Middleware für die Ausnahmebehandlung erneut die ursprüngliche Ausnahme aus.
Im folgenden Beispiel fügt UseExceptionHandler die Middleware zur Ausnahmebehandlung in Nichtentwicklungsumgebungen hinzu:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Die Razor Pages-App-Vorlage stellt im Ordner Pages eine Fehlerseite (.cshtml
) und eine PageModel-Klasse (ErrorModel
) bereit. Die Projektvorlage für eine MVC-App enthält eine Error
-Aktionsmethode und eine Fehleransicht für den Home-Controller.
Die Middleware für die Ausnahmebehandlung führt die Anforderung unter Verwendung der ursprünglichen HTTP-Methode erneut aus. Wenn ein Endpunkt für die Fehlerbehandlung auf bestimmte HTTP-Methoden beschränkt ist, wird er nur für diese Methoden ausgeführt. Beispielsweise wird eine MVC-Controller-Aktion, die das Attribut [HttpGet]
verwendet, nur für GET-Anforderungen ausgeführt. Um sicherzustellen, dass alle Anforderungen die benutzerdefinierte Seite für die Fehlerbehandlung erreichen, beschränken Sie die Endpunkte nicht auf bestimmte HTTP-Methoden.
So behandeln Sie Ausnahmen unterschiedlich, basierend auf der ursprünglichen HTTP-Methode:
- Für Razor Pages erstellen Sie mehrere Handlermethoden. Verwenden Sie beispielsweise
OnGet
zum Behandeln von GET-Ausnahmen undOnPost
zum Behandeln von POST-Ausnahmen. - Für MVC wenden Sie HTTP-Verbattribute auf mehrere Aktionen an. Verwenden Sie beispielsweise
[HttpGet]
zum Behandeln von GET-Ausnahmen und[HttpPost]
zum Behandeln von POST-Ausnahmen.
Um nicht authentifizierten Benutzern die Anzeige der benutzerdefinierten Seite für die Fehlerbehandlung zu ermöglichen, stellen Sie sicher, dass der anonyme Zugriff unterstützt wird.
Zugreifen auf die Ausnahme
Verwenden Sie IExceptionHandlerPathFeature, um auf die Ausnahme oder den Pfad der ursprünglichen Anforderung in einem Fehlerhandler zuzugreifen. Im folgenden Beispiel wird IExceptionHandlerPathFeature
verwendet, um weitere Informationen zur ausgelösten Ausnahme zu erhalten:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "The file was not found.";
}
if (exceptionHandlerPathFeature?.Path == "/")
{
ExceptionMessage ??= string.Empty;
ExceptionMessage += " Page: Home.";
}
}
}
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
Lambda-Ausdruck für Ausnahmehandler
Eine Alternative zu einer benutzerdefinierten Ausnahmebehandlungsseite ist das Angeben eines Lambda-Ausdrucks für UseExceptionHandler. Die Verwendung eines Lambda-Ausdrucks ermöglicht den Zugriff auf den Fehler, bevor die Antwort zurückgegeben wird.
Der folgende Code verwendet einen Lambdaausdruck für die Ausnahmebehandlung:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// using static System.Net.Mime.MediaTypeNames;
context.Response.ContentType = Text.Plain;
await context.Response.WriteAsync("An exception was thrown.");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(" The file was not found.");
}
if (exceptionHandlerPathFeature?.Path == "/")
{
await context.Response.WriteAsync(" Page: Home.");
}
});
});
app.UseHsts();
}
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
UseStatusCodePages
Die ASP.NET Core-App stellt für HTTP-Fehlerstatuscodes wie 404 – Nicht gefunden standardmäßig keine Statuscodeseite zur Verfügung. Wenn die App einen HTTP-Fehlerstatuscode im Bereich 400 bis 599 ohne Text festlegt, werden der Statuscode und ein leerer Antworttext zurückgegeben. Um für gängige Statuscodes einfache Handler im Textformat zu aktivieren, rufen Sie UseStatusCodePages in Program.cs
auf:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Rufen Sie UseStatusCodePages
vor der Middleware für die Anforderungsverarbeitung auf. Rufen Sie beispielsweise UseStatusCodePages
vor der Middleware für statische Dateien und der Middleware für Endpunkte auf.
Wenn UseStatusCodePages
nicht verwendet wird, wird beim Navigieren zu einer URL ohne Endpunkt eine browserabhängige Fehlermeldung zurückgegeben, die angibt, dass der Endpunkt nicht gefunden werden kann. Wenn UseStatusCodePages
aufgerufen wird, gibt der Browser die folgende Antwort zurück:
Status Code: 404; Not Found
UseStatusCodePages
wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
Hinweis
Die Middleware für Statuscodeseiten erfasst keine Ausnahmen. Um eine benutzerdefinierte Fehlerbehandlungsseite bereitzustellen, verwenden Sie die Ausnahmehandlerseite.
UseStatusCodePages mit Formatzeichenfolge
Um den Inhaltstyp und Text der Antwort anzupassen, verwenden Sie die Überladung von UseStatusCodePages, die einen Inhaltstyp und eine Formatierungszeichenfolge erfordert:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// using static System.Net.Mime.MediaTypeNames;
app.UseStatusCodePages(Text.Plain, "Status Code Page: {0}");
Im vorangehenden Code ist {0}
ein Platzhalter für den Fehlercode.
UseStatusCodePages
mit Formatzeichenfolge wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
UseStatusCodePages mit Lambda-Ausdruck
Um benutzerdefinierten Code für die Fehlerbehandlung und das Schreiben von Antworten anzugeben, verwenden Sie die Überladung von UseStatusCodePages, die einen Lambda-Ausdruck verwendet:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async statusCodeContext =>
{
// using static System.Net.Mime.MediaTypeNames;
statusCodeContext.HttpContext.Response.ContentType = Text.Plain;
await statusCodeContext.HttpContext.Response.WriteAsync(
$"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});
UseStatusCodePages
mit Lambdaausdruck wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
UseStatusCodePagesWithRedirects
Die Erweiterungsmethode UseStatusCodePagesWithRedirects:
- Sendet den Statuscode 302 Found (Gefunden) an den Client.
- Leitet den Client an den in der URL-Vorlage angegebenen Fehlerbehandlungsendpunkt weiter. Der Fehlerbehandlungsendpunkt zeigt in der Regel Fehlerinformationen an und gibt den HTTP-Code 200 zurück.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Die URL-Vorlage kann, wie im vorangehenden Code gezeigt, einen {0}
-Platzhalter für den Statuscode enthalten. Wenn die URL-Vorlage mit einer Tilde (~
) beginnt, wird ~
durch die Angabe für PathBase
der App ersetzt. Wenn Sie in der App einen Endpunkt angeben, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Den Client an einen anderen Endpunkt umleiten, in der Regel in Fällen, in denen eine andere App den Fehler verarbeitet. Für Web-Apps gibt die Adressleiste des Browsers des Clients den umgeleiteten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der anfänglichen Umleitungsantwort nicht beibehalten und zurückgeben.
UseStatusCodePagesWithReExecute
Die Erweiterungsmethode UseStatusCodePagesWithReExecute:
- Gibt den ursprünglichen Statuscode an den Client zurück.
- Generiert den Antworttext durch die erneute Ausführung der Anforderungspipeline mithilfe eines alternativen Pfads.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Wenn in der App ein Endpunkt angegeben ist, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Die Anforderung ohne Umleitung an einen anderen Endpunkt verarbeiten. Für Web-Apps gibt die Adressleiste des Browsers des Clients den ursprünglich angeforderten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der Antwort beibehalten und zurückgeben.
Die URL-Vorlage muss mit /
beginnen und kann den Platzhalter {0}
für den Statuscode enthalten. Um den Statuscode als Abfragezeichenfolgenparameter zu übergeben, übergeben Sie ein zweites Argument an UseStatusCodePagesWithReExecute
. Beispiel:
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Der Endpunkt, der den Fehler verarbeitet, kann die ursprüngliche URL abrufen, die den Fehler generiert hat (siehe folgendes Beispiel):
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = string.Join(
statusCodeReExecuteFeature.OriginalPathBase,
statusCodeReExecuteFeature.OriginalPath,
statusCodeReExecuteFeature.OriginalQueryString);
}
}
}
Deaktivieren von Statuscodeseiten
Verwenden Sie das Attribut [SkipStatusCodePages], um Statuscodeseiten für einen MVC-Controller oder eine MVC-Aktionsmethode zu deaktivieren.
Verwenden Sie IStatusCodePagesFeature, um Statuscodeseiten für bestimmte Anforderungen in der Handlermethode von Razor Pages oder in einem MVC-Controller zu deaktivieren:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Ausnahmebehandlungscode
Code auf Seiten zur Ausnahmebehandlung kann ebenfalls Ausnahmen auslösen. Produktionsfehlerseiten sollten gründlich getestet werden. Achten Sie darauf, dabei keine eigenen Ausnahmen auszulösen.
Antwortheader
Nachdem die Header für eine Antwort gesendet wurden:
- Die App kann den Statuscode der Antwort nicht ändern.
- Weder Ausnahmeseiten noch Handler können ausgeführt werden. Die Antwort muss abgeschlossen oder die Verbindung unterbrochen werden.
Sichere Ausnahmebehandlung
Neben der Ausnahmebehandlungslogik in einer App kann die HTTP-Serverimplementierung einige Ausnahmebehandlungen durchführen. Wenn der Server eine Ausnahme erfasst, bevor die Antwortheader gesendet werden, sendet der Server die Antwort 500 - Internal Server Error
ohne Antworttext. Wenn der Server eine Ausnahme auffängt, nachdem die Antwortheader gesendet wurden, schließt der Server die Verbindung. Anforderungen, die nicht von der App verarbeitet werden, werden vom Server verarbeitet. Jede Ausnahme, die bei der Anforderungsverarbeitung durch den Server auftritt, wird durch die Ausnahmebehandlung des Servers verarbeitet. Die benutzerdefinierten Fehlerseiten der App, Middleware zur Fehlerbehandlung und Filter haben keine Auswirkungen auf dieses Verhalten.
Fehlerbehandlung während des Starts
Nur auf Hostebene können Ausnahmen behandelt werden, die während des Starts einer App auftreten. Der Host kann für das Erfassen von Startfehlern und Erfassen detaillierter Fehler konfiguriert werden.
Die Hostingebene kann nur dann für einen beim Start erfassten Fehler eine Fehlerseite anzeigen, wenn der Fehler nach der Bindung an die Hostadresse bzw. den Port auftritt. Wenn die Bindung misslingt:
- Die Hostebene protokolliert eine kritische Ausnahme.
- Der DotNet-Prozess stürzt ab.
- Wenn der HTTP-Server Kestrel heißt, wird keine Fehlerseite angezeigt.
Wenn sie auf IIS (oder Azure App Service) oder IIS Express ausgeführt wird, wird ein Prozessfehler 502.5 vom ASP.NET Core-Modul zurückgegeben, wenn der Prozess nicht starten kann. Weitere Informationen finden Sie unter Problembehandlung bei ASP.NET Core in Azure App Service und IIS.
Datenbank-Fehlerseite
Der Ausnahmefilter der Datenbankentwicklerseite AddDatabaseDeveloperPageExceptionFilter erfasst datenbankbezogene Ausnahmen, die mithilfe von Entity Framework Core-Migrationen aufgelöst werden können. Wenn diese Ausnahmen auftreten, wird eine HTML-Antwort mit Details zu möglichen Aktionen zum Beheben des Problems generiert. Diese Seite ist nur in der Entwicklungsumgebung aktiviert. Der folgende Code fügt den Ausnahmefilter der Datenbankentwicklerseite hinzu:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Ausnahmefilter
In MVC-Apps können Ausnahmefilter global oder auf einen Controller oder eine Aktion bezogen konfiguriert werden. In Razor Pages-Apps können sie global oder auf ein Seitenmodell bezogen konfiguriert werden. Diese Filter verarbeiten jede nicht behandelte Ausnahme, die während der Ausführung eine Controlleraktion oder eines anderen Filters auftritt. Weitere Informationen finden Sie unter Filter in ASP.NET Core.
Ausnahmefilter eignen sich zum Auffangen von Ausnahmen, die in MVC-Aktionen ausgelöst werden. Sie sind jedoch nicht so flexibel wie die integrierte Middleware für die Ausnahmebehandlung, UseExceptionHandler. Es wird empfohlen, UseExceptionHandler
zu verwenden, wenn Sie für die Fehlerbehandlung auf Grundlage einer ausgewählten MVC-Aktion eine andere Strategie auswählen müssen.
Modellstatusfehler
Informationen zum Behandeln von Modellstatusfehlern finden Sie unter Modellbindung und Modellvalidierung.
Zusätzliche Ressourcen
Von Kirk Larkin, Tom Dykstra und Steve Smith
Dieser Artikel beschreibt grundsätzliche Vorgehensweisen zur Behandlung von Fehlern in ASP.NET Core-Web-Apps. Weitere Informationen zu Web-APIs finden Sie unter Behandeln von Fehlern in ASP.NET Core-controllerbasierten Web-APIs.
Anzeigen oder Herunterladen von Beispielcode (Informationen zum Herunterladen.) Die Registerkarte „Netzwerk“ in den F12-Entwicklertools im Browser ist beim Testen der Beispiel-App nützlich.
Seite mit Ausnahmen für Entwickler
Die Seite mit Ausnahmen für Entwickler enthält ausführliche Informationen zu unbehandelten Anforderungsausnahmen. Die ASP.NET Core-Vorlagen generieren den folgenden Code:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Der vorangehende hervorgehobene Code aktiviert die Seite mit Ausnahmen für Entwickler, wenn die App in der Entwicklungsumgebung ausgeführt wird.
Die Vorlagen platzieren UseDeveloperExceptionPage am Anfang der Middlewarepipeline, sodass die in der nachfolgenden Middleware ausgelösten unbehandelten Ausnahmen abgefangen werden.
Der vorangehende Code aktiviert die Seite mit Ausnahmen für Entwickler nur dann, wenn die App in der Entwicklungsumgebung ausgeführt wird. Bei Ausführung der App in der Produktionsumgebung dürfen keine detaillierten Informationen zu den Ausnahmen öffentlich angezeigt werden. 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)
- Header
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.
Seite „Ausnahmehandler“
Um eine benutzerdefinierte Fehlerbehandlungsseite für die Produktionsumgebung zu konfigurieren, rufen Sie UseExceptionHandler auf. Die Aufgaben der Middleware zur Ausnahmebehandlung:
- Dient zum Abfangen und Protokollieren unbehandelter Ausnahmen.
- Führt erneut die Anforderung in einer anderen Pipeline im angegebenen Pfad aus. Die Anforderung wird nicht erneut ausgeführt, wenn die Antwort gestartet wurde. Der von der Vorlage generierte Code führt die Anforderung erneut mit dem
/Error
-Pfad aus.
Warnung
Wenn die alternative Pipeline eigenständig eine Ausnahme auslöst, löst die Middleware für die Ausnahmebehandlung erneut die ursprüngliche Ausnahme aus.
Im folgenden Beispiel fügt UseExceptionHandler die Middleware zur Ausnahmebehandlung in Nichtentwicklungsumgebungen hinzu:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Die Razor Pages-App-Vorlage stellt im Ordner Pages eine Fehlerseite (.cshtml
) und eine PageModel-Klasse (ErrorModel
) bereit. Die Projektvorlage für eine MVC-App enthält eine Error
-Aktionsmethode und eine Fehleransicht für den Home-Controller.
Die Middleware für die Ausnahmebehandlung führt die Anforderung unter Verwendung der ursprünglichen HTTP-Methode erneut aus. Wenn ein Endpunkt für die Fehlerbehandlung auf bestimmte HTTP-Methoden beschränkt ist, wird er nur für diese Methoden ausgeführt. Beispielsweise wird eine MVC-Controller-Aktion, die das Attribut [HttpGet]
verwendet, nur für GET-Anforderungen ausgeführt. Um sicherzustellen, dass alle Anforderungen die benutzerdefinierte Seite für die Fehlerbehandlung erreichen, beschränken Sie die Endpunkte nicht auf bestimmte HTTP-Methoden.
So behandeln Sie Ausnahmen unterschiedlich, basierend auf der ursprünglichen HTTP-Methode:
- Für Razor Pages erstellen Sie mehrere Handlermethoden. Verwenden Sie beispielsweise
OnGet
zum Behandeln von GET-Ausnahmen undOnPost
zum Behandeln von POST-Ausnahmen. - Für MVC wenden Sie HTTP-Verbattribute auf mehrere Aktionen an. Verwenden Sie beispielsweise
[HttpGet]
zum Behandeln von GET-Ausnahmen und[HttpPost]
zum Behandeln von POST-Ausnahmen.
Um nicht authentifizierten Benutzern die Anzeige der benutzerdefinierten Seite für die Fehlerbehandlung zu ermöglichen, stellen Sie sicher, dass der anonyme Zugriff unterstützt wird.
Zugreifen auf die Ausnahme
Verwenden Sie IExceptionHandlerPathFeature, um auf die Ausnahme oder den Pfad der ursprünglichen Anforderung in einem Fehlerhandler zuzugreifen. Der folgende Code fügt dem Standard Pages/Error.cshtml.cs
die von den ASP.NET Core-Vorlagen generierte ExceptionMessage
hinzu:
[ResponseCache(Duration=0, Location=ResponseCacheLocation.None, NoStore=true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string ExceptionMessage { get; set; }
private readonly ILogger<ErrorModel> _logger;
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "File error thrown";
_logger.LogError(ExceptionMessage);
}
if (exceptionHandlerPathFeature?.Path == "/index")
{
ExceptionMessage += " from home page";
}
}
}
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
So testen Sie die Ausnahme in der Beispiel-App
- Legen Sie die Umgebung auf Produktion fest.
- Entfernen Sie die Kommentare aus
webBuilder.UseStartup<Startup>();
inProgram.cs
. - Wählen Sie auf der Startseite Ausnahme auslösen aus.
Lambda-Ausdruck für Ausnahmehandler
Eine Alternative zu einer benutzerdefinierten Ausnahmebehandlungsseite ist das Angeben eines Lambda-Ausdrucks für UseExceptionHandler. Die Verwendung eines Lambda-Ausdrucks ermöglicht den Zugriff auf den Fehler, bevor die Antwort zurückgegeben wird.
Der folgende Code verwendet einen Lambdaausdruck für die Ausnahmebehandlung:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;;
context.Response.ContentType = "text/html";
await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
await context.Response.WriteAsync("ERROR!<br><br>\r\n");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync(
"File error thrown!<br><br>\r\n");
}
await context.Response.WriteAsync(
"<a href=\"/\">Home</a><br>\r\n");
await context.Response.WriteAsync("</body></html>\r\n");
await context.Response.WriteAsync(new string(' ', 512));
});
});
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Warnung
Stellen Sie keine vertraulichen Fehlerinformationen aus IExceptionHandlerFeature oder IExceptionHandlerPathFeature für Clients bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
So testen Sie den Lambdaausdruck für die Ausnahmebehandlung in der Beispiel-App
- Legen Sie die Umgebung auf Produktion fest.
- Entfernen Sie die Kommentare aus
webBuilder.UseStartup<StartupLambda>();
inProgram.cs
. - Wählen Sie auf der Startseite Ausnahme auslösen aus.
UseStatusCodePages
Die ASP.NET Core-App stellt für HTTP-Fehlerstatuscodes wie 404 – Nicht gefunden standardmäßig keine Statuscodeseite zur Verfügung. Wenn die App einen HTTP-Fehlerstatuscode im Bereich 400 bis 599 ohne Text festlegt, werden der Statuscode und ein leerer Antworttext zurückgegeben. Verwenden Sie zum Bereitstellen von Statuscodeseiten Middleware für Statuscodeseiten. Um für gängige Statuscodes einfache Handler im Textformat zu aktivieren, rufen Sie in der Startup.Configure
-Methode UseStatusCodePages auf:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Rufen Sie UseStatusCodePages
vor der Middleware für die Anforderungsverarbeitung auf. Rufen Sie beispielsweise UseStatusCodePages
vor der Middleware für statische Dateien und der Middleware für Endpunkte auf.
Wenn UseStatusCodePages
nicht verwendet wird, wird beim Navigieren zu einer URL ohne Endpunkt eine browserabhängige Fehlermeldung zurückgegeben, die angibt, dass der Endpunkt nicht gefunden werden kann. Navigieren Sie zum Beispiel zu Home/Privacy2
. Wenn UseStatusCodePages
aufgerufen wird, gibt der Browser Folgendes zurück:
Status Code: 404; Not Found
UseStatusCodePages
wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
So testen Sie UseStatusCodePages
in der Beispiel-App
- Legen Sie die Umgebung auf Produktion fest.
- Entfernen Sie die Kommentare aus
webBuilder.UseStartup<StartupUseStatusCodePages>();
inProgram.cs
. - Wählen Sie die Links auf der Seite home auf der Startseite.
Hinweis
Die Middleware für Statuscodeseiten erfasst keine Ausnahmen. Um eine benutzerdefinierte Fehlerbehandlungsseite bereitzustellen, verwenden Sie die Ausnahmehandlerseite.
UseStatusCodePages mit Formatzeichenfolge
Um den Inhaltstyp und Text der Antwort anzupassen, verwenden Sie die Überladung von UseStatusCodePages, die einen Inhaltstyp und eine Formatierungszeichenfolge erfordert:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(
"text/plain", "Status code page, status code: {0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Im vorangehenden Code ist {0}
ein Platzhalter für den Fehlercode.
UseStatusCodePages
mit Formatzeichenfolge wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
Um UseStatusCodePages
in der Beispiel-App zu testen, entfernen Sie die Kommentare aus webBuilder.UseStartup<StartupFormat>();
in Program.cs
.
UseStatusCodePages mit Lambda-Ausdruck
Um benutzerdefinierten Code für die Fehlerbehandlung und das Schreiben von Antworten anzugeben, verwenden Sie die Überladung von UseStatusCodePages, die einen Lambda-Ausdruck verwendet:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
UseStatusCodePages
mit Lambdaausdruck wird normalerweise nicht in der Produktionsumgebung verwendet, da diese Methode eine Meldung zurückgibt, die für Benutzer nicht nützlich ist.
Um UseStatusCodePages
in der Beispiel-App zu testen, entfernen Sie die Kommentare aus webBuilder.UseStartup<StartupStatusLambda>();
in Program.cs
.
UseStatusCodePagesWithRedirects
Die Erweiterungsmethode UseStatusCodePagesWithRedirects:
- Sendet den Statuscode 302 Found (Gefunden) an den Client.
- Leitet den Client an den in der URL-Vorlage angegebenen Fehlerbehandlungsendpunkt weiter. Der Fehlerbehandlungsendpunkt zeigt in der Regel Fehlerinformationen an und gibt den HTTP-Code 200 zurück.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/MyStatusCode?code={0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Die URL-Vorlage kann, wie im vorangehenden Code gezeigt, einen {0}
-Platzhalter für den Statuscode enthalten. Wenn die URL-Vorlage mit einer Tilde (~
) beginnt, wird ~
durch die Angabe für PathBase
der App ersetzt. Wenn Sie in der App einen Endpunkt angeben, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen. Ein Razor Pages-Beispiel finden Sie unter Pages/MyStatusCode.cshtml in der Beispiel-App.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Den Client an einen anderen Endpunkt umleiten, in der Regel in Fällen, in denen eine andere App den Fehler verarbeitet. Für Web-Apps gibt die Adressleiste des Browsers des Clients den umgeleiteten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der anfänglichen Umleitungsantwort nicht beibehalten und zurückgeben.
Um UseStatusCodePages
in der Beispiel-App zu testen, entfernen Sie die Kommentare aus webBuilder.UseStartup<StartupSCredirect>();
in Program.cs
.
UseStatusCodePagesWithReExecute
Die Erweiterungsmethode UseStatusCodePagesWithReExecute:
- Gibt den ursprünglichen Statuscode an den Client zurück.
- Generiert den Antworttext durch die erneute Ausführung der Anforderungspipeline mithilfe eines alternativen Pfads.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/MyStatusCode2", "?code={0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Wenn in der App ein Endpunkt angegeben ist, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen. Stellen Sie sicher, dass UseStatusCodePagesWithReExecute
vor UseRouting
platziert wird, damit die Anforderung an die Statusseite umgeleitet werden kann. Ein Razor Pages-Beispiel finden Sie unter Pages/MyStatusCode2.cshtml in der Beispiel-App.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Die Anforderung ohne Umleitung an einen anderen Endpunkt verarbeiten. Für Web-Apps gibt die Adressleiste des Browsers des Clients den ursprünglich angeforderten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der Antwort beibehalten und zurückgeben.
Die Vorlagen für URL und Abfragezeichenfolgen können für den Statuscode einen Platzhalter ({0}
) enthalten. Die URL-Vorlage muss mit einem Schrägstrich (/
) beginnen.
Der Endpunkt, der den Fehler verarbeitet, kann die ursprüngliche URL abrufen, die den Fehler generiert hat (siehe folgendes Beispiel):
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class MyStatusCode2Model : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string ErrorStatusCode { get; set; }
public string OriginalURL { get; set; }
public bool ShowOriginalURL => !string.IsNullOrEmpty(OriginalURL);
public void OnGet(string code)
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
ErrorStatusCode = code;
var statusCodeReExecuteFeature = HttpContext.Features.Get<
IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
OriginalURL =
statusCodeReExecuteFeature.OriginalPathBase
+ statusCodeReExecuteFeature.OriginalPath
+ statusCodeReExecuteFeature.OriginalQueryString;
}
}
}
Ein Razor Pages-Beispiel finden Sie unter Pages/MyStatusCode2.cshtml in der Beispiel-App.
Um UseStatusCodePages
in der Beispiel-App zu testen, entfernen Sie die Kommentare aus webBuilder.UseStartup<StartupSCreX>();
in Program.cs
.
Deaktivieren von Statuscodeseiten
Verwenden Sie das Attribut [SkipStatusCodePages], um Statuscodeseiten für einen MVC-Controller oder eine MVC-Aktionsmethode zu deaktivieren.
Verwenden Sie IStatusCodePagesFeature, um Statuscodeseiten für bestimmte Anforderungen in der Handlermethode von Razor Pages oder in einem MVC-Controller zu deaktivieren:
public void OnGet()
{
// using Microsoft.AspNetCore.Diagnostics;
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
}
Ausnahmebehandlungscode
Code auf Seiten zur Ausnahmebehandlung kann ebenfalls Ausnahmen auslösen. Produktionsfehlerseiten sollten gründlich getestet werden. Achten Sie darauf, dabei keine eigenen Ausnahmen auszulösen.
Antwortheader
Nachdem die Header für eine Antwort gesendet wurden:
- Die App kann den Statuscode der Antwort nicht ändern.
- Weder Ausnahmeseiten noch Handler können ausgeführt werden. Die Antwort muss abgeschlossen oder die Verbindung unterbrochen werden.
Sichere Ausnahmebehandlung
Neben der Ausnahmebehandlungslogik in einer App kann die HTTP-Serverimplementierung einige Ausnahmebehandlungen durchführen. Wenn der Server eine Ausnahme erfasst, bevor die Antwortheader gesendet werden, sendet der Server die Antwort 500 - Internal Server Error
ohne Antworttext. Wenn der Server eine Ausnahme auffängt, nachdem die Antwortheader gesendet wurden, schließt der Server die Verbindung. Anforderungen, die nicht von der App verarbeitet werden, werden vom Server verarbeitet. Jede Ausnahme, die bei der Anforderungsverarbeitung durch den Server auftritt, wird durch die Ausnahmebehandlung des Servers verarbeitet. Die benutzerdefinierten Fehlerseiten der App, Middleware zur Fehlerbehandlung und Filter haben keine Auswirkungen auf dieses Verhalten.
Fehlerbehandlung während des Starts
Nur auf Hostebene können Ausnahmen behandelt werden, die während des Starts einer App auftreten. Der Host kann für das Erfassen von Startfehlern und Erfassen detaillierter Fehler konfiguriert werden.
Die Hostingebene kann nur dann für einen beim Start erfassten Fehler eine Fehlerseite anzeigen, wenn der Fehler nach der Bindung an die Hostadresse bzw. den Port auftritt. Wenn die Bindung misslingt:
- Die Hostebene protokolliert eine kritische Ausnahme.
- Der DotNet-Prozess stürzt ab.
- Wenn der HTTP-Server Kestrel heißt, wird keine Fehlerseite angezeigt.
Wenn sie auf IIS (oder Azure App Service) oder IIS Express ausgeführt wird, wird ein Prozessfehler 502.5 vom ASP.NET Core-Modul zurückgegeben, wenn der Prozess nicht starten kann. Weitere Informationen finden Sie unter Problembehandlung bei ASP.NET Core in Azure App Service und IIS.
Datenbank-Fehlerseite
Der Ausnahmefilter der Datenbankentwicklerseite AddDatabaseDeveloperPageExceptionFilter
erfasst datenbankbezogene Ausnahmen, die mithilfe von Entity Framework Core-Migrationen aufgelöst werden können. Wenn diese Ausnahmen auftreten, wird eine HTML-Antwort mit Details zu möglichen Aktionen zum Beheben des Problems generiert. Diese Seite ist nur in der Entwicklungsumgebung aktiviert. Der folgende Code wurde von den ASP.NET Core Razor Pages-Vorlagen generiert, als einzelne Benutzerkonten angegeben wurden:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
}
Ausnahmefilter
In MVC-Apps können Ausnahmefilter global oder auf einen Controller oder eine Aktion bezogen konfiguriert werden. In Razor Pages-Apps können sie global oder auf ein Seitenmodell bezogen konfiguriert werden. Diese Filter verarbeiten jede nicht behandelte Ausnahme, die während der Ausführung eine Controlleraktion oder eines anderen Filters auftritt. Weitere Informationen finden Sie unter Filter in ASP.NET Core.
Ausnahmefilter eignen sich zum Auffangen von Ausnahmen, die in MVC-Aktionen ausgelöst werden. Sie sind jedoch nicht so flexibel wie die integrierte Middleware für die Ausnahmebehandlung, UseExceptionHandler
. Es wird empfohlen, UseExceptionHandler
zu verwenden, wenn Sie für die Fehlerbehandlung auf Grundlage einer ausgewählten MVC-Aktion eine andere Strategie auswählen müssen.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Modellstatusfehler
Informationen zum Behandeln von Modellstatusfehlern finden Sie unter Modellbindung und Modellvalidierung.
Zusätzliche Ressourcen
Von Tom Dykstra und Steve Smith
Dieser Artikel beschreibt grundsätzliche Vorgehensweisen zur Behandlung von Fehlern in ASP.NET Core-Web-Apps. Weitere Informationen zu Web-APIs finden Sie unter Behandeln von Fehlern in ASP.NET Core-controllerbasierten Web-APIs.
Anzeigen oder Herunterladen von Beispielcode (Informationen zum Herunterladen.)
Seite mit Ausnahmen für Entwickler
Die Seite mit Ausnahmen für Entwickler enthält ausführliche Informationen zu Anforderungsausnahmen. Die ASP.NET Core-Vorlagen generieren den folgenden Code:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Der vorangehende Code aktiviert die Seite mit Ausnahmen für Entwickler, wenn die App in der Entwicklungsumgebung ausgeführt wird.
Die Vorlagen platzieren UseDeveloperExceptionPage vor jeder Middleware, sodass Ausnahmen in der nachfolgenden Middleware abgefangen werden.
Der vorangehende Code aktiviert die Seite mit Ausnahmen für Entwickler nur dann, wenn die App in der Entwicklungsumgebung ausgeführt wird. Bei Ausführung der App in der Produktionsumgebung sollten keine detaillierten Informationen zu den Ausnahmen öffentlich angezeigt werden. Weitere Informationen zum Konfigurieren der Umgebung finden Sie unter Verwenden mehrerer Umgebungen in ASP.NET Core.
Die Seite mit Ausnahmen für Entwickler enthält die folgenden Informationen zu der Ausnahme und der Anforderung:
- Stapelüberwachung
- Abfragezeichenfolgeparameter, sofern vorhanden
- Cookies (sofern vorhanden)
- Headers
Seite „Ausnahmehandler“
Um eine benutzerdefinierte Fehlerbehandlung für die Produktionsumgebung zu konfigurieren, verwenden Sie Middleware zur Ausnahmebehandlung. Die Middleware:
- Dient zum Abfangen und Protokollieren von Ausnahmen.
- Führt die Anforderung für die angegebene Seite oder den Controller in einer anderen Pipeline erneut aus. Die Anforderung wird nicht erneut ausgeführt, wenn die Antwort gestartet wurde. Der von der Vorlage generierte Code führt die Anforderung erneut mit
/Error
aus.
Im folgenden Beispiel fügt UseExceptionHandler die Middleware zur Ausnahmebehandlung in Nichtentwicklungsumgebungen hinzu:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Die Razor Pages-App-Vorlage stellt im Ordner Pages eine Fehlerseite ( .cshtml
) und PageModel-Klasse (ErrorModel
) bereit. Die Projektvorlage für eine MVC-App enthält eine Fehleraktionsmethode und eine Fehleransicht im Home-Controller.
Markieren Sie die Aktionsmethode für die Fehlerbehandlung nicht mit HTTP-Methodenattributen wie HttpGet
. Durch explizite Verben könnte bei einigen Anforderungen verhindert werden, dass diese Methode zum Einsatz kommt. Lassen Sie den anonymen Zugriff auf die Methode zu, wenn nicht authentifizierten Benutzern die Fehleransicht angezeigt werden soll.
Zugreifen auf die Ausnahme
Verwenden Sie IExceptionHandlerPathFeature, um auf die Ausnahme oder den Pfad der ursprünglichen Anforderung in einem Controller für die Fehlerbehandlung oder auf einer Seite zuzugreifen:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string ExceptionMessage { get; set; }
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var exceptionHandlerPathFeature =
HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
ExceptionMessage = "File error thrown";
}
if (exceptionHandlerPathFeature?.Path == "/index")
{
ExceptionMessage += " from home page";
}
}
}
Warnung
Stellen Sie Clients keine vertraulichen Fehlerinformationen bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
Legen Sie die Umgebung auf Produktionen fest, und erzwingen Sie eine Ausnahme, um die vorherige Seite zur Ausnahmebehandlung zu aktivieren.
Lambda-Ausdruck für Ausnahmehandler
Eine Alternative zu einer benutzerdefinierten Ausnahmebehandlungsseite ist das Angeben eines Lambda-Ausdrucks für UseExceptionHandler. Die Verwendung eines Lambda-Ausdrucks ermöglicht den Zugriff auf den Fehler, bevor die Antwort zurückgegeben wird.
Hier ist ein Beispiel der Verwendung eines Lambda-Ausdrucks für die Ausnahmebehandlung:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/html";
await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
await context.Response.WriteAsync("ERROR!<br><br>\r\n");
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
await context.Response.WriteAsync("File error thrown!<br><br>\r\n");
}
await context.Response.WriteAsync("<a href=\"/\">Home</a><br>\r\n");
await context.Response.WriteAsync("</body></html>\r\n");
await context.Response.WriteAsync(new string(' ', 512)); // IE padding
});
});
app.UseHsts();
}
Im vorangehenden Code wird await context.Response.WriteAsync(new string(' ', 512));
hinzugefügt, sodass der Internet Explorer-Browser die Fehlermeldung anstelle einer IE-Fehlermeldung anzeigt. Weitere Informationen finden Sie in diesem GitHub-Issue.
Warnung
Stellen Sie keine vertraulichen Fehlerinformationen aus IExceptionHandlerFeature oder IExceptionHandlerPathFeature für Clients bereit. Die Bereitstellung von Fehlern ist ein Sicherheitsrisiko.
Um in der Beispiel-App das Ergebnis der Lambdafunktion für die Ausnahmebehandlung anzuzeigen, verwenden Sie die Präprozessordirektiven ProdEnvironment
und ErrorHandlerLambda
und wählen Sie auf der Seite home die Option Ausnahme auslösen aus.
UseStatusCodePages
Ihre ASP.NET Core-App stellt für HTTP-Statuscodes wie 404 – Nicht gefunden standardmäßig keine Statuscodeseite zur Verfügung. Die App gibt einen Statuscode und einen leeren Antworttext zurück. Verwenden Sie zum Bereitstellen von Statuscodeseiten Middleware für Statuscodeseiten.
Die Middleware wird vom Paket Microsoft.AspNetCore.Diagnostics zur Verfügung gestellt.
Um für gängige Statuscodes einfache Handler im Textformat zu aktivieren, rufen Sie in der Startup.Configure
-Methode UseStatusCodePages auf:
app.UseStatusCodePages();
Rufen Sie UseStatusCodePages
vor Middleware zur Anforderungsverarbeitung auf (z.B. Middleware für statische Dateien und MVC-Middleware).
Wenn UseStatusCodePages
nicht verwendet wird, wird beim Navigieren zu einer URL ohne Endpunkt eine browserabhängige Fehlermeldung zurückgegeben, die angibt, dass der Endpunkt nicht gefunden werden kann. Navigieren Sie zum Beispiel zu Home/Privacy2
. Wenn UseStatusCodePages
aufgerufen wird, gibt der Browser Folgendes zurück:
Status Code: 404; Not Found
UseStatusCodePages mit Formatzeichenfolge
Um den Inhaltstyp und Text der Antwort anzupassen, verwenden Sie die Überladung von UseStatusCodePages, die einen Inhaltstyp und eine Formatierungszeichenfolge erfordert:
app.UseStatusCodePages(
"text/plain", "Status code page, status code: {0}");
UseStatusCodePages mit Lambda-Ausdruck
Um benutzerdefinierten Code für die Fehlerbehandlung und das Schreiben von Antworten anzugeben, verwenden Sie die Überladung von UseStatusCodePages, die einen Lambda-Ausdruck verwendet:
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
UseStatusCodePagesWithRedirects
Die Erweiterungsmethode UseStatusCodePagesWithRedirects:
- Sendet den Statuscode 302 Found (Gefunden) an den Client.
- Der Client wird an den in der URL-Vorlage angegebenen Standort umgeleitet.
app.UseStatusCodePagesWithRedirects("/StatusCode?code={0}");
Die URL-Vorlage kann, wie im Beispiel gezeigt, einen {0}
-Platzhalter für den Statuscode enthalten. Wenn die URL-Vorlage mit einer Tilde (~
) beginnt, wird ~
durch die Angabe für PathBase
der App ersetzt. Wenn Sie in der App auf einen Endpunkt verweisen, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen. Ein Razor Pages-Beispiel finden Sie unter Pages/StatusCode.cshtml
in der Beispiel-App.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Den Client an einen anderen Endpunkt umleiten, in der Regel in Fällen, in denen eine andere App den Fehler verarbeitet. Für Web-Apps gibt die Adressleiste des Browsers des Clients den umgeleiteten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der anfänglichen Umleitungsantwort nicht beibehalten und zurückgeben.
UseStatusCodePagesWithReExecute
Die Erweiterungsmethode UseStatusCodePagesWithReExecute:
- Gibt den ursprünglichen Statuscode an den Client zurück.
- Generiert den Antworttext durch die erneute Ausführung der Anforderungspipeline mithilfe eines alternativen Pfads.
app.UseStatusCodePagesWithReExecute("/StatusCode","?code={0}");
Wenn Sie in der App auf einen Endpunkt verweisen, müssen Sie eine MVC-Ansicht oder Razor-Seite für den Endpunkt erstellen. Stellen Sie sicher, dass UseStatusCodePagesWithReExecute
vor UseRouting
platziert wird, damit die Anforderung an die Statusseite umgeleitet werden kann. Ein Razor Pages-Beispiel finden Sie unter Pages/StatusCode.cshtml
in der Beispiel-App.
Diese Methode wird häufig verwendet, wenn die App Folgendes tun soll:
- Die Anforderung ohne Umleitung an einen anderen Endpunkt verarbeiten. Für Web-Apps gibt die Adressleiste des Browsers des Clients den ursprünglich angeforderten Endpunkt wieder.
- Den ursprünglichen Statuscode mit der Antwort beibehalten und zurückgeben.
Die Vorlagen für URL und Abfragezeichenfolgen können für den Statuscode einen Platzhalter ({0}
) enthalten. Die URL-Vorlage muss mit einem Schrägstrich (/
) beginnen. Wenn Sie im Pfad einen Platzhalter verwenden, vergewissern Sie sich, dass der Endpunkt (Seite oder Controller) das Pfadsegment verarbeiten kann. Eine Razor Page für Fehler sollte z. B. den Wert des optionalen Pfadsegments mit der @page
-Anweisung akzeptieren:
@page "{code?}"
Der Endpunkt, der den Fehler verarbeitet, kann die ursprüngliche URL abrufen, die den Fehler generiert hat (siehe folgendes Beispiel):
var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
OriginalURL =
statusCodeReExecuteFeature.OriginalPathBase
+ statusCodeReExecuteFeature.OriginalPath
+ statusCodeReExecuteFeature.OriginalQueryString;
}
Markieren Sie die Aktionsmethode für die Fehlerbehandlung nicht mit HTTP-Methodenattributen wie HttpGet
. Durch explizite Verben könnte bei einigen Anforderungen verhindert werden, dass diese Methode zum Einsatz kommt. Lassen Sie den anonymen Zugriff auf die Methode zu, wenn nicht authentifizierten Benutzern die Fehleransicht angezeigt werden soll.
Deaktivieren von Statuscodeseiten
Verwenden Sie das Attribut [SkipStatusCodePages]
, um Statuscodeseiten für einen MVC-Controller oder eine MVC-Aktionsmethode zu deaktivieren.
Verwenden Sie IStatusCodePagesFeature, um Statuscodeseiten für bestimmte Anforderungen in der Handlermethode von Razor Pages oder in einem MVC-Controller zu deaktivieren:
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
Ausnahmebehandlungscode
Code auf Seiten zur Ausnahmebehandlung kann Ausnahmen auslösen. Es ist häufig empfehlenswert, wenn Produktionsfehlerseiten nur statische Inhalte aufweisen.
Antwortheader
Nachdem die Header für eine Antwort gesendet wurden:
- Die App kann den Statuscode der Antwort nicht ändern.
- Weder Ausnahmeseiten noch Handler können ausgeführt werden. Die Antwort muss abgeschlossen oder die Verbindung unterbrochen werden.
Sichere Ausnahmebehandlung
Neben der Ausnahmebehandlungslogik in Ihrer App kann die HTTP-Serverimplementierung einige Ausnahmebehandlungen durchführen. Wenn der Server eine Ausnahme erfasst, bevor die Antwortheader gesendet werden, sendet der Server die Antwort 500 – Interner Serverfehler ohne Antworttext. Wenn der Server eine Ausnahme auffängt, nachdem die Antwortheader gesendet wurden, schließt der Server die Verbindung. Anforderungen, die nicht von Ihrer App verarbeitet werden, werden vom Server verarbeitet. Jede Ausnahme, die bei der Anforderungsverarbeitung durch den Server auftritt, wird durch die Ausnahmebehandlung des Servers verarbeitet. Die benutzerdefinierten Fehlerseiten der App, Middleware zur Fehlerbehandlung und Filter haben keine Auswirkungen auf dieses Verhalten.
Fehlerbehandlung während des Starts
Nur auf Hostebene können Ausnahmen behandelt werden, die während des Starts einer App auftreten. Der Host kann für das Erfassen von Startfehlern und Erfassen detaillierter Fehler konfiguriert werden.
Die Hostingebene kann nur dann für einen beim Start erfassten Fehler eine Fehlerseite anzeigen, wenn der Fehler nach der Bindung an die Hostadresse bzw. den Port auftritt. Wenn die Bindung misslingt:
- Die Hostebene protokolliert eine kritische Ausnahme.
- Der DotNet-Prozess stürzt ab.
- Wenn der HTTP-Server Kestrel heißt, wird keine Fehlerseite angezeigt.
Wenn sie auf IIS (oder Azure App Service) oder IIS Express ausgeführt wird, wird ein Prozessfehler 502.5 vom ASP.NET Core-Modul zurückgegeben, wenn der Prozess nicht starten kann. Weitere Informationen finden Sie unter Problembehandlung bei ASP.NET Core in Azure App Service und IIS.
Datenbank-Fehlerseite
Die Middleware „Datenbank-Fehlerseite“ erfasst datenbankbezogene Ausnahmen, die mithilfe von Entity Framework-Migrationen aufgelöst werden können. Wenn diese Ausnahmen auftreten, wird eine HTML-Antwort mit Details zu möglichen Aktionen zum Beheben des Problems generiert. Diese Seite darf nur in der Entwicklungsumgebung aktiviert werden. Aktivieren Sie die Seite, indem Sie Startup.Configure
Code hinzufügen:
if (env.IsDevelopment())
{
app.UseDatabaseErrorPage();
}
UseDatabaseErrorPage benötigt das Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore-NuGet-Paket.
Ausnahmefilter
In MVC-Apps können Ausnahmefilter global oder auf einen Controller oder eine Aktion bezogen konfiguriert werden. In Razor Pages-Apps können sie global oder auf ein Seitenmodell bezogen konfiguriert werden. Diese Filter verarbeiten jede nicht behandelte Ausnahme, die während der Ausführung eine Controlleraktion oder eines anderen Filters auftritt. Weitere Informationen finden Sie unter Filter in ASP.NET Core.
Tipp
Ausnahmefilter eignen sich zum Auffangen von Ausnahmen, die in MVC-Aktionen auftreten. Sie sind jedoch nicht so flexibel wie Middleware für die Ausnahmebehandlung. Es wird empfohlen, die Middleware zu verwenden. Verwenden Sie Filter nur dann, wenn Sie für die Fehlerbehandlung auf Grundlage einer ausgewählten MVC-Aktion eine andere Strategie wählen müssen.
Modellstatusfehler
Informationen zum Behandeln von Modellstatusfehlern finden Sie unter Modellbindung und Modellvalidierung.