Zpracování chyb v ASP.NET Core
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v tématu .NET a .NET Core Zásady podpory. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Aktuální verzi najdete ve verzi .NET 8 tohoto článku.
Od Tom Dykstra
Tento článek popisuje běžné přístupy ke zpracování chyb ve webových aplikacích ASP.NET Core. Podívejte se také na chyby v ASP.NET webových rozhraních API založených na jádru a zpracování chyb v minimálních rozhraních API.
Pokyny Blazor pro zpracování chyb, které přidávají nebo nahrazují pokyny v tomto článku, najdete v tématu Zpracování chyb v aplikacích ASP.NET CoreBlazor.
Stránka výjimky pro vývojáře
Na stránce výjimka pro vývojáře se zobrazují podrobné informace o neošetřených výjimkách požadavků. Používá DeveloperExceptionPageMiddleware se k zaznamenání synchronních a asynchronních výjimek z kanálu HTTP a k vygenerování chybových odpovědí. Stránka výjimky vývojáře se spouští v rané fázi kanálu middlewaru, aby bylo možné zachytit neošetřené výjimky vyvolané v middlewaru, které následuje.
ASP.NET aplikace Core ve výchozím nastavení povolí stránku výjimky pro vývojáře, pokud jsou obě:
- Běží ve vývojovém prostředí.
- Aplikace byla vytvořena s aktuálními šablonami, tj. pomocí .WebApplication.CreateBuilder
Aplikace vytvořené pomocí dřívějších šablon, tj. pomocí WebHost.CreateDefaultBuilder, mohou povolit stránku výjimky vývojáře voláním app.UseDeveloperExceptionPage
.
Upozorňující
Nepovolujte stránku výjimek vývojáře, pokud aplikace není spuštěná ve vývojovém prostředí. Nesdílejte podrobné informace o výjimce veřejně, když aplikace běží v produkčním prostředí. Další informace o konfiguraci prostředí najdete v tématu Použití více prostředí v ASP.NET Core.
Stránka výjimky pro vývojáře může obsahovat následující informace o výjimce a požadavku:
- Trasování zásobníku
- Parametry řetězce dotazu, pokud nějaké
- Soubory cookie, pokud nějaké
- Hlavičky
- Metadata koncového bodu, pokud existuje
Na stránce výjimky pro vývojáře není zaručeno, že poskytnete žádné informace. Protokolování slouží k úplným informacím o chybě.
Následující obrázek ukazuje ukázkovou stránku výjimky vývojáře s animací, která zobrazuje karty a zobrazené informace:
V reakci na požadavek s hlavičkou Accept: text/plain
vrátí stránka výjimky vývojáře místo HTML prostý text. Příklad:
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
Stránka obslužné rutiny výjimky
Chcete-li nakonfigurovat vlastní stránku zpracování chyb pro produkční prostředí, zavolejte UseExceptionHandler. Tento middleware pro zpracování výjimek:
- Zachytává a zaznamenává neošetřené výjimky.
- Znovu spustí požadavek v alternativním kanálu pomocí uvedené cesty. Pokud se odpověď spustila, požadavek se znovu nespustí. Vygenerovaný kód šablony znovu spustí požadavek pomocí
/Error
cesty.
Upozorňující
Pokud alternativní kanál vyvolá výjimku vlastní, middleware zpracování výjimek znovu zvětšuje původní výjimku.
Vzhledem k tomu, že tento middleware může kanál požadavku znovu spustit:
- Middleware musí zpracovávat opakování se stejným požadavkem. Obvykle to znamená, že po zavolání
_next
nebo uložení zpracování do mezipamětiHttpContext
na zařízení, aby se zabránilo jeho opětovnému vytvoření. Při práci s textem požadavku to znamená ukládání do vyrovnávací paměti nebo ukládání výsledků do mezipaměti, jako je čtečka formulářů. - UseExceptionHandler(IApplicationBuilder, String) Pro přetížení, které se používá v šablonách, je změněna pouze cesta požadavku a směrovací data jsou vymazána. Všechna data požadavku, jako jsou hlavičky, metoda a položky, se znovu používají tak, jak jsou.
- Služby s vymezeným oborem zůstávají stejné.
V následujícím příkladu UseExceptionHandler přidá middleware pro zpracování výjimek v prostředích, která nejsou vývojová:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Šablona Razor aplikace Pages poskytuje ve složce Pages chybovou stránku (.cshtml
) a PageModel třídu (ErrorModel
). V případě aplikace MVC obsahuje šablona projektu metodu Error
akce a zobrazení Chyba kontroleru Home .
Middleware zpracování výjimek znovu spustí požadavek pomocí původní metody HTTP. Pokud je koncový bod obslužné rutiny chyby omezen na konkrétní sadu metod HTTP, spustí se pouze pro tyto metody HTTP. Například akce kontroleru MVC, která používá [HttpGet]
atribut, se spouští pouze pro požadavky GET. Abyste zajistili, že všechny požadavky dosáhnou vlastní stránky zpracování chyb, neomezovat je na konkrétní sadu metod HTTP.
Zpracování výjimek odlišně na základě původní metody HTTP:
- Pro Razor Stránky vytvořte více metod obslužné rutiny. Slouží
OnGet
například ke zpracování výjimek GET a zpracováníOnPost
výjimek POST. - Pro MVC použijte atributy příkazů HTTP na více akcí. Slouží
[HttpGet]
například ke zpracování výjimek GET a zpracování[HttpPost]
výjimek POST.
Pokud chcete umožnit neověřeným uživatelům zobrazit vlastní stránku pro zpracování chyb, ujistěte se, že podporuje anonymní přístup.
Přístup k výjimce
Slouží IExceptionHandlerPathFeature k přístupu k výjimce a původní cestě požadavku v obslužné rutině chyby. Následující příklad používá IExceptionHandlerPathFeature
k získání dalších informací o výjimce, která byla vyvolán:
[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.";
}
}
}
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
Lambda obslužné rutiny výjimek
Alternativou k vlastní stránce obslužné rutiny výjimky je poskytnutí lambda UseExceptionHandler. Použití lambda umožňuje přístup k chybě před vrácením odpovědi.
Následující kód používá lambda pro zpracování výjimek:
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();
}
Dalším způsobem použití lambda je nastavení stavového kódu na základě typu výjimky, jako v následujícím příkladu:
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
});
}
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
IExceptionHandler
IExceptionHandler je rozhraní, které vývojářům poskytuje zpětné volání pro zpracování známých výjimek v centrálním umístění.
IExceptionHandler
implementace jsou registrovány voláním IServiceCollection.AddExceptionHandler<T>
. Životnost IExceptionHandler
instance je singleton. Je možné přidat více implementací a volají se v zaregistrované objednávce.
Pokud obslužná rutina výjimky zpracovává požadavek, může se vrátit true
a zastavit zpracování. Pokud žádná obslužná rutina výjimky nezpracuje výjimku, ovládací prvek se vrátí do výchozího chování a možností z middlewaru. Pro zpracovávané a neošetřené výjimky se vygenerují různé metriky a protokoly.
Následující příklad ukazuje implementaci 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);
}
}
}
Následující příklad ukazuje, jak zaregistrovat IExceptionHandler
implementaci pro injektáž závislostí:
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
Při spuštění předchozího kódu ve vývojovém prostředí:
- Volá se
CustomExceptionHandler
jako první pro zpracování výjimky. - Po protokolování výjimky
TryHandleAsync
metoda vrátífalse
, takže se zobrazí stránka výjimky vývojáře.
V jiných prostředích:
- Volá se
CustomExceptionHandler
jako první pro zpracování výjimky. - Po protokolování výjimky
TryHandleAsync
metoda vrátífalse
, takže/Error
stránka je zobrazena.
UseStatusCodePages
Ve výchozím nastavení aplikace ASP.NET Core neposkytuje stavovou znakovou stránku pro stavové kódy chyb HTTP, například 404 – Nenalezena. Když aplikace nastaví stavový kód chyby HTTP 400-599, který nemá tělo, vrátí stavový kód a prázdný text odpovědi. Pokud chcete povolit výchozí obslužné rutiny jen pro text pro běžné stavové kódy chyb, zavolejte do UseStatusCodePages Program.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Před zpracováním middlewaru žádostí zavolejte UseStatusCodePages
. Například zavolejte UseStatusCodePages
před middlewarem statického souboru a middlewarem koncových bodů.
Pokud UseStatusCodePages
se nepoužívá, přechod na adresu URL bez koncového bodu vrátí chybovou zprávu závislá na prohlížeči, která značí, že se koncový bod nenašel. Při UseStatusCodePages
zavolání vrátí prohlížeč následující odpověď:
Status Code: 404; Not Found
UseStatusCodePages
se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
Poznámka:
Middleware stavových kódů nezachytává výjimky. Pokud chcete poskytnout vlastní stránku zpracování chyb, použijte stránku obslužné rutiny výjimky.
UseStatusCodePages s formátovacím řetězcem
Pokud chcete přizpůsobit typ obsahu odpovědi a text, použijte přetížení UseStatusCodePages , které přebírá typ obsahu a formátovací řetězec:
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}");
V předchozím kódu {0}
je zástupný symbol pro kód chyby.
UseStatusCodePages
formátovací řetězec se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
PoužitíStatusCodePages s lambda
Pokud chcete zadat vlastní zpracování chyb a kód pro zápis odpovědí, použijte přetížení UseStatusCodePages , které přebírá výraz lambda:
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
s lambda se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
UseStatusCodePagesWithRedirects
Metoda UseStatusCodePagesWithRedirects rozšíření:
- Odešle klientovi stavový kód 302 .
- Přesměruje klienta na koncový bod zpracování chyb zadaný v šabloně adresy URL. Koncový bod zpracování chyb obvykle zobrazuje informace o chybě a vrací http 200.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Šablona adresy URL může obsahovat {0}
zástupný symbol pro stavový kód, jak je znázorněno v předchozím kódu. Pokud šablona adresy URL začíná vlnovkou ~
, ~
nahradí se aplikací PathBase
. Při zadávání koncového bodu v aplikaci vytvořte zobrazení nebo Razor stránku MVC pro koncový bod.
Tato metoda se běžně používá v případě, že aplikace:
- Měl by přesměrovat klienta na jiný koncový bod, obvykle v případech, kdy jiná aplikace zpracovává chybu. U webových aplikací se adresní řádek prohlížeče klienta odráží přesměrovaný koncový bod.
- Nemělo by se zachovat a vrátit původní stavový kód s počáteční odpovědí přesměrování.
UseStatusCodePagesWithReExecute
Metoda UseStatusCodePagesWithReExecute rozšíření:
- Vygeneruje tělo odpovědi opětovným spuštěním kanálu požadavku pomocí alternativní cesty.
- Nezmění stavový kód před opětovným spuštěním kanálu ani po jeho opětovném spuštění.
Nové spuštění kanálu může změnit stavový kód odpovědi, protože nový kanál má plnou kontrolu nad stavovým kódem. Pokud nový kanál nezmění stavový kód, původní stavový kód se odešle klientovi.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Pokud je zadaný koncový bod v aplikaci, vytvořte zobrazení nebo Razor stránku MVC pro koncový bod.
Tato metoda se běžně používá, když by aplikace měla:
- Zpracujte požadavek bez přesměrování na jiný koncový bod. U webových aplikací se adresní řádek prohlížeče klienta odráží původně požadovaný koncový bod.
- Zachování a vrácení původního stavového kódu s odpovědí
Šablona adresy URL musí začínat /
a může obsahovat zástupný symbol {0}
pro stavový kód. Chcete-li předat stavový kód jako parametr řetězce dotazu, předejte druhý argument do UseStatusCodePagesWithReExecute
. Příklad:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Koncový bod, který chybu zpracuje, může získat původní adresu URL, která chybu vygenerovala, jak je znázorněno v následujícím příkladu:
[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}";
}
}
}
Vzhledem k tomu, že tento middleware může kanál požadavku znovu spustit:
- Middleware musí zpracovávat opakování se stejným požadavkem. Obvykle to znamená, že po zavolání
_next
nebo uložení zpracování do mezipamětiHttpContext
na zařízení, aby se zabránilo jeho opětovnému vytvoření. Při práci s textem požadavku to znamená ukládání do vyrovnávací paměti nebo ukládání výsledků do mezipaměti, jako je čtečka formulářů. - Služby s vymezeným oborem zůstávají stejné.
Zakázat stavové kódové stránky
Chcete-li zakázat stránky stavového kódu pro kontroler MVC nebo metodu akce, použijte atribut [SkipStatusCodePages].
Chcete-li zakázat stavové kódové stránky pro konkrétní požadavky v Razor metodě obslužné rutiny stránky nebo v kontroleru MVC, použijte IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kód pro zpracování výjimek
Kód na stránkách zpracování výjimek může také vyvolat výjimky. Produkční chybové stránky by se měly důkladně testovat a pečlivě se postarat, aby nedocházelo k výjimkám jejich vlastních.
Hlavičky odpovědi
Po odeslání hlaviček odpovědi:
- Aplikace nemůže změnit stavový kód odpovědi.
- Všechny stránky výjimek nebo obslužné rutiny se nedají spustit. Odpověď musí být dokončena nebo přerušeno připojení.
Zpracování výjimek serveru
Kromě logiky zpracování výjimek v aplikaci může implementace serveru HTTP zpracovávat některé výjimky. Pokud server zachytí výjimku před odesláním hlaviček odpovědi, server odešle 500 - Internal Server Error
odpověď bez textu odpovědi. Pokud server zachytí výjimku po odeslání hlaviček odpovědi, server připojení zavře. Požadavky, které aplikace nezpracuje, zpracovává server. Všechny výjimky, ke kterým dochází, když server zpracovává požadavek, se zpracovává zpracováním výjimek serveru. Vlastní chybové stránky aplikace, middleware pro zpracování výjimek a filtry toto chování neovlivní.
Ošetření výjimek při spuštění
Pouze vrstva hostování může zpracovávat výjimky, které probíhají při spuštění aplikace. Hostitel lze nakonfigurovat tak, aby zaznamenával chyby při spuštění a zaznamenával podrobné chyby.
Vrstva hostování může zobrazit chybovou stránku zachycené chyby při spuštění pouze v případě, že k chybě dojde po vazbě adresy hostitele nebo portu. Pokud se vazba nezdaří:
- Vrstva hostování zaznamená kritickou výjimku.
- Proces dotnet se chybově ukončí.
- Pokud je Kestrelserver HTTP, nezobrazí se žádná chybová stránka.
Pokud je proces spuštěný ve službě IIS (nebo ve službě Aplikace Azure) nebo IIS Express, vrátí modul ASP.NET Core chybu procesu 502.5. Další informace najdete v tématu Řešení potíží ASP.NET Core ve službě Aplikace Azure a službě IIS.
Chybová stránka databáze
Filtr AddDatabaseDeveloperPageExceptionFilter výjimek stránky pro vývojáře databáze zachycuje výjimky související s databází, které je možné vyřešit pomocí migrací Entity Framework Core. Pokud dojde k těmto výjimkám, vygeneruje se odpověď HTML s podrobnostmi o možných akcích k vyřešení problému. Tato stránka je povolená pouze ve vývojovém prostředí. Následující kód přidá filtr výjimek stránky pro vývojáře databáze:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Filtry výjimek
V aplikacích MVC je možné nakonfigurovat filtry výjimek globálně nebo podle kontroleru nebo podle akce. V Razor aplikacích Pages je možné je nakonfigurovat globálně nebo podle modelu stránky. Tyto filtry zpracovávají všechny neošetřené výjimky, ke kterým dochází během provádění akce kontroleru nebo jiného filtru. Další informace najdete v tématu Filtry v ASP.NET Core.
Filtry výjimek jsou užitečné pro zachycení výjimek, ke kterým dochází v rámci akcí MVC, ale nejsou tak flexibilní jako integrovaný middlewareUseExceptionHandler pro zpracování výjimek. Doporučujeme použít UseExceptionHandler
, pokud nepotřebujete provádět zpracování chyb odlišně podle toho, jakou akci MVC zvolíte.
Chyby stavu modelu
Informace o tom, jak zpracovávat chyby stavu modelu, naleznete v tématu Vazby modelu a Ověření modelu.
Podrobnosti o problému
Podrobnosti o problému nejsou jediným formátem odpovědi, který popisuje chybu rozhraní HTTP API, ale běžně se používají k hlášení chyb pro rozhraní HTTP API.
Služba podrobností problému implementuje IProblemDetailsService rozhraní, které podporuje vytváření podrobností o problému v ASP.NET Core. Metoda AddProblemDetails(IServiceCollection) rozšíření při IServiceCollection registraci výchozí IProblemDetailsService
implementace.
V aplikacích ASP.NET Core generuje následující middleware při zavolání podrobnosti o problému odpovědi AddProblemDetails
HTTP, s výjimkou případů, kdy Accept
hlavička HTTP požadavku neobsahuje jeden z typů obsahu podporovaných zaregistrovaným IProblemDetailsWriter (výchozí: application/json
):
- ExceptionHandlerMiddleware: Vygeneruje odpověď na podrobnosti o problému, pokud není definována vlastní obslužná rutina.
- StatusCodePagesMiddleware: Ve výchozím nastavení vygeneruje odpověď podrobností o problému.
- DeveloperExceptionPageMiddleware: Vygeneruje odpověď na podrobnosti o problému při vývoji, pokud hlavička
Accept
HTTP požadavku neobsahujetext/html
.
Následující kód nakonfiguruje aplikaci tak, aby vygenerovala odpověď na podrobnosti o problému pro všechny odpovědi na chyby klienta HTTP a serveru, které ještě nemají základní obsah:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
V další části se dozvíte, jak přizpůsobit text odpovědi s podrobnostmi o problému.
Přizpůsobení podrobností o problému
Automatické vytváření ProblemDetails
můžete přizpůsobit pomocí některé z následujících možností:
- Použití
ProblemDetailsOptions.CustomizeProblemDetails
- Použití vlastního
IProblemDetailsWriter
IProblemDetailsService
Volání v middlewaru
CustomizeProblemDetails
operace
Vygenerované podrobnosti o problému lze přizpůsobit pomocí CustomizeProblemDetailsa vlastní nastavení se použijí na všechny automaticky generované podrobnosti o problému.
Následující kód používá ProblemDetailsOptions k nastavení CustomizeProblemDetails:
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();
Výsledek koncového HTTP Status 400 Bad Request
bodu například vytvoří následující text odpovědi s podrobnostmi o problému:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Zvyk IProblemDetailsWriter
Pro IProblemDetailsWriter pokročilá přizpůsobení je možné vytvořit implementaci.
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));
}
}
Poznámka: Při použití vlastní IProblemDetailsWriter
, vlastní IProblemDetailsWriter
musí být registrován před voláním AddRazorPages, AddControllers, , AddControllersWithViewsnebo AddMvc:
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();
Podrobnosti o problému z middlewaru
Alternativním přístupem k použití s ProblemDetailsOptions CustomizeProblemDetails je nastavení v middlewaru ProblemDetails . Odpověď s podrobnostmi o problému může být napsána voláním IProblemDetailsService.WriteAsync
:
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();
V předchozím kódu minimální koncové body /divide
rozhraní API a /squareroot
vrátí očekávanou vlastní odpověď na problém při zadávání chyb.
Koncové body kontroleru rozhraní API vrací výchozí odpověď na problém při zadávání chyb, nikoli vlastní odpověď na problém. Výchozí odpověď na problém je vrácena, protože kontroler rozhraní API zapisoval do streamu odpovědi, podrobnosti o problému pro stavové kódy chyb, před IProblemDetailsService.WriteAsync
voláním a odpověď se znovu nezapíše .
Následující ValuesController
vrátí hodnotu BadRequestResult, která zapisuje do streamu odpovědi, a proto zabraňuje vrácení vlastní odpovědi na problém.
[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));
}
}
Následující Values3Controller
vrátí ControllerBase.Problem
výsledek očekávaného vlastního problému:
[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));
}
}
Vytvoření datové části ProblemDetails pro výjimky
Zvažte následující aplikaci:
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();
Pokud dojde k výjimce v prostředích, která nejsou vývojová, jedná se o standardní odpověď ProblemDetails, která se vrátí klientovi:
{
"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"
}
U většiny aplikací je předchozí kód vše, co je potřeba pro výjimky. Následující část ale ukazuje, jak získat podrobnější odpovědi na problémy.
Alternativou k vlastní stránce obslužné rutiny výjimky je poskytnutí lambda UseExceptionHandler. Použití lambda umožňuje přístup k chybě a napsání odpovědi s podrobnostmi o problému pomocí 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();
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
Alternativním přístupem k vygenerování podrobností o problému je použití balíčku NuGet jiného výrobce Hellang.Middleware.ProblemDetails , který lze použít k mapování výjimek a chyb klienta na podrobnosti o problému.
Další materiály
- Zobrazení nebo stažení ukázkového kódu (postup stažení)
- Řešení potíží s ASP.NET Core v Azure App Service a ve službě IIS
- Řešení běžných chyb v Azure App Service a ve službě IIS souvisejících s ASP.NET Core
- Zpracování chyb ve webových rozhraních API založených na řadiči jádra ASP.NET
- Zpracování chyb v minimálních rozhraních API
Od Tom Dykstra
Tento článek popisuje běžné přístupy ke zpracování chyb ve webových aplikacích ASP.NET Core. Podívejte se také na chyby v ASP.NET webových rozhraních API založených na jádru a zpracování chyb v minimálních rozhraních API.
Stránka výjimky pro vývojáře
Na stránce výjimka pro vývojáře se zobrazují podrobné informace o neošetřených výjimkách požadavků. ASP.NET aplikace Core ve výchozím nastavení povolí stránku výjimky pro vývojáře, pokud jsou obě:
- Běží ve vývojovém prostředí.
- Aplikace vytvořená s aktuálními šablonami, to znamená pomocí WebApplication.CreateBuilder. Aplikace vytvořené pomocí příkazu
WebHost.CreateDefaultBuilder
musí povolit stránku výjimky vývojáře volánímapp.UseDeveloperExceptionPage
Configure
.
Stránka výjimky vývojáře se spouští v rané fázi kanálu middlewaru, aby bylo možné zachytit neošetřené výjimky vyvolané v middlewaru, které následuje.
Podrobné informace o výjimce by se neměly zobrazovat veřejně při spuštění aplikace v produkčním prostředí. Další informace o konfiguraci prostředí najdete v tématu Použití více prostředí v ASP.NET Core.
Stránka výjimky pro vývojáře může obsahovat následující informace o výjimce a požadavku:
- Trasování zásobníku
- Parametry řetězce dotazu, pokud nějaké
- Soubory cookie, pokud nějaké
- Hlavičky
Na stránce výjimky pro vývojáře není zaručeno, že poskytnete žádné informace. Protokolování slouží k úplným informacím o chybě.
Stránka obslužné rutiny výjimky
Chcete-li nakonfigurovat vlastní stránku zpracování chyb pro produkční prostředí, zavolejte UseExceptionHandler. Tento middleware pro zpracování výjimek:
- Zachytává a zaznamenává neošetřené výjimky.
- Znovu spustí požadavek v alternativním kanálu pomocí uvedené cesty. Pokud se odpověď spustila, požadavek se znovu nespustí. Vygenerovaný kód šablony znovu spustí požadavek pomocí
/Error
cesty.
Upozorňující
Pokud alternativní kanál vyvolá výjimku vlastní, middleware zpracování výjimek znovu zvětšuje původní výjimku.
Vzhledem k tomu, že tento middleware může kanál požadavku znovu spustit:
- Middleware musí zpracovávat opakování se stejným požadavkem. Obvykle to znamená, že po zavolání
_next
nebo uložení zpracování do mezipamětiHttpContext
na zařízení, aby se zabránilo jeho opětovnému vytvoření. Při práci s textem požadavku to znamená ukládání do vyrovnávací paměti nebo ukládání výsledků do mezipaměti, jako je čtečka formulářů. - UseExceptionHandler(IApplicationBuilder, String) Pro přetížení, které se používá v šablonách, je změněna pouze cesta požadavku a směrovací data jsou vymazána. Všechna data požadavku, jako jsou hlavičky, metoda a položky, se znovu používají tak, jak jsou.
- Služby s vymezeným oborem zůstávají stejné.
V následujícím příkladu UseExceptionHandler přidá middleware pro zpracování výjimek v prostředích, která nejsou vývojová:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Šablona Razor aplikace Pages poskytuje ve složce Pages chybovou stránku (.cshtml
) a PageModel třídu (ErrorModel
). V případě aplikace MVC obsahuje šablona projektu metodu Error
akce a zobrazení Chyba kontroleru Home .
Middleware zpracování výjimek znovu spustí požadavek pomocí původní metody HTTP. Pokud je koncový bod obslužné rutiny chyby omezen na konkrétní sadu metod HTTP, spustí se pouze pro tyto metody HTTP. Například akce kontroleru MVC, která používá [HttpGet]
atribut, se spouští pouze pro požadavky GET. Abyste zajistili, že všechny požadavky dosáhnou vlastní stránky zpracování chyb, neomezovat je na konkrétní sadu metod HTTP.
Zpracování výjimek odlišně na základě původní metody HTTP:
- Pro Razor Stránky vytvořte více metod obslužné rutiny. Slouží
OnGet
například ke zpracování výjimek GET a zpracováníOnPost
výjimek POST. - Pro MVC použijte atributy příkazů HTTP na více akcí. Slouží
[HttpGet]
například ke zpracování výjimek GET a zpracování[HttpPost]
výjimek POST.
Pokud chcete umožnit neověřeným uživatelům zobrazit vlastní stránku pro zpracování chyb, ujistěte se, že podporuje anonymní přístup.
Přístup k výjimce
Slouží IExceptionHandlerPathFeature k přístupu k výjimce a původní cestě požadavku v obslužné rutině chyby. Následující příklad používá IExceptionHandlerPathFeature
k získání dalších informací o výjimce, která byla vyvolán:
[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.";
}
}
}
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
Lambda obslužné rutiny výjimek
Alternativou k vlastní stránce obslužné rutiny výjimky je poskytnutí lambda UseExceptionHandler. Použití lambda umožňuje přístup k chybě před vrácením odpovědi.
Následující kód používá lambda pro zpracování výjimek:
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();
}
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
IExceptionHandler
IExceptionHandler je rozhraní, které vývojářům poskytuje zpětné volání pro zpracování známých výjimek v centrálním umístění.
IExceptionHandler
implementace jsou registrovány voláním IServiceCollection.AddExceptionHandler<T>
. Životnost IExceptionHandler
instance je singleton. Je možné přidat více implementací a volají se v zaregistrované objednávce.
Pokud obslužná rutina výjimky zpracovává požadavek, může se vrátit true
a zastavit zpracování. Pokud žádná obslužná rutina výjimky nezpracuje výjimku, ovládací prvek se vrátí do výchozího chování a možností z middlewaru. Pro zpracovávané a neošetřené výjimky se vygenerují různé metriky a protokoly.
Následující příklad ukazuje implementaci 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);
}
}
}
Následující příklad ukazuje, jak zaregistrovat IExceptionHandler
implementaci pro injektáž závislostí:
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
Při spuštění předchozího kódu ve vývojovém prostředí:
- Volá se
CustomExceptionHandler
jako první pro zpracování výjimky. - Po protokolování výjimky
TryHandleException
metoda vrátífalse
, takže se zobrazí stránka výjimky vývojáře.
V jiných prostředích:
- Volá se
CustomExceptionHandler
jako první pro zpracování výjimky. - Po protokolování výjimky
TryHandleException
metoda vrátífalse
, takže/Error
stránka je zobrazena.
UseStatusCodePages
Ve výchozím nastavení aplikace ASP.NET Core neposkytuje stavovou znakovou stránku pro stavové kódy chyb HTTP, například 404 – Nenalezena. Když aplikace nastaví stavový kód chyby HTTP 400-599, který nemá tělo, vrátí stavový kód a prázdný text odpovědi. Pokud chcete povolit výchozí obslužné rutiny jen pro text pro běžné stavové kódy chyb, zavolejte do UseStatusCodePages Program.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Před zpracováním middlewaru žádostí zavolejte UseStatusCodePages
. Například zavolejte UseStatusCodePages
před middlewarem statického souboru a middlewarem koncových bodů.
Pokud UseStatusCodePages
se nepoužívá, přechod na adresu URL bez koncového bodu vrátí chybovou zprávu závislá na prohlížeči, která značí, že se koncový bod nenašel. Při UseStatusCodePages
zavolání vrátí prohlížeč následující odpověď:
Status Code: 404; Not Found
UseStatusCodePages
se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
Poznámka:
Middleware stavových kódů nezachytává výjimky. Pokud chcete poskytnout vlastní stránku zpracování chyb, použijte stránku obslužné rutiny výjimky.
UseStatusCodePages s formátovacím řetězcem
Pokud chcete přizpůsobit typ obsahu odpovědi a text, použijte přetížení UseStatusCodePages , které přebírá typ obsahu a formátovací řetězec:
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}");
V předchozím kódu {0}
je zástupný symbol pro kód chyby.
UseStatusCodePages
formátovací řetězec se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
PoužitíStatusCodePages s lambda
Pokud chcete zadat vlastní zpracování chyb a kód pro zápis odpovědí, použijte přetížení UseStatusCodePages , které přebírá výraz lambda:
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
s lambda se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
UseStatusCodePagesWithRedirects
Metoda UseStatusCodePagesWithRedirects rozšíření:
- Odešle klientovi stavový kód 302 .
- Přesměruje klienta na koncový bod zpracování chyb zadaný v šabloně adresy URL. Koncový bod zpracování chyb obvykle zobrazuje informace o chybě a vrací http 200.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Šablona adresy URL může obsahovat {0}
zástupný symbol pro stavový kód, jak je znázorněno v předchozím kódu. Pokud šablona adresy URL začíná vlnovkou ~
, ~
nahradí se aplikací PathBase
. Při zadávání koncového bodu v aplikaci vytvořte zobrazení nebo Razor stránku MVC pro koncový bod.
Tato metoda se běžně používá v případě, že aplikace:
- Měl by přesměrovat klienta na jiný koncový bod, obvykle v případech, kdy jiná aplikace zpracovává chybu. U webových aplikací se adresní řádek prohlížeče klienta odráží přesměrovaný koncový bod.
- Nemělo by se zachovat a vrátit původní stavový kód s počáteční odpovědí přesměrování.
UseStatusCodePagesWithReExecute
Metoda UseStatusCodePagesWithReExecute rozšíření:
- Vygeneruje tělo odpovědi opětovným spuštěním kanálu požadavku pomocí alternativní cesty.
- Nezmění stavový kód před opětovným spuštěním kanálu ani po jeho opětovném spuštění.
Nové spuštění kanálu může změnit stavový kód odpovědi, protože nový kanál má plnou kontrolu nad stavovým kódem. Pokud nový kanál nezmění stavový kód, původní stavový kód se odešle klientovi.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Pokud je zadaný koncový bod v aplikaci, vytvořte zobrazení nebo Razor stránku MVC pro koncový bod.
Tato metoda se běžně používá, když by aplikace měla:
- Zpracujte požadavek bez přesměrování na jiný koncový bod. U webových aplikací se adresní řádek prohlížeče klienta odráží původně požadovaný koncový bod.
- Zachování a vrácení původního stavového kódu s odpovědí
Šablona adresy URL musí začínat /
a může obsahovat zástupný symbol {0}
pro stavový kód. Chcete-li předat stavový kód jako parametr řetězce dotazu, předejte druhý argument do UseStatusCodePagesWithReExecute
. Příklad:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Koncový bod, který chybu zpracuje, může získat původní adresu URL, která chybu vygenerovala, jak je znázorněno v následujícím příkladu:
[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}";
}
}
}
Vzhledem k tomu, že tento middleware může kanál požadavku znovu spustit:
- Middleware musí zpracovávat opakování se stejným požadavkem. Obvykle to znamená, že po zavolání
_next
nebo uložení zpracování do mezipamětiHttpContext
na zařízení, aby se zabránilo jeho opětovnému vytvoření. Při práci s textem požadavku to znamená ukládání do vyrovnávací paměti nebo ukládání výsledků do mezipaměti, jako je čtečka formulářů. - Služby s vymezeným oborem zůstávají stejné.
Zakázat stavové kódové stránky
Chcete-li zakázat stránky stavového kódu pro kontroler MVC nebo metodu akce, použijte atribut [SkipStatusCodePages].
Chcete-li zakázat stavové kódové stránky pro konkrétní požadavky v Razor metodě obslužné rutiny stránky nebo v kontroleru MVC, použijte IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kód pro zpracování výjimek
Kód na stránkách zpracování výjimek může také vyvolat výjimky. Produkční chybové stránky by se měly důkladně testovat a pečlivě se postarat, aby nedocházelo k výjimkám jejich vlastních.
Hlavičky odpovědi
Po odeslání hlaviček odpovědi:
- Aplikace nemůže změnit stavový kód odpovědi.
- Všechny stránky výjimek nebo obslužné rutiny se nedají spustit. Odpověď musí být dokončena nebo přerušeno připojení.
Zpracování výjimek serveru
Kromě logiky zpracování výjimek v aplikaci může implementace serveru HTTP zpracovávat některé výjimky. Pokud server zachytí výjimku před odesláním hlaviček odpovědi, server odešle 500 - Internal Server Error
odpověď bez textu odpovědi. Pokud server zachytí výjimku po odeslání hlaviček odpovědi, server připojení zavře. Požadavky, které aplikace nezpracuje, zpracovává server. Všechny výjimky, ke kterým dochází, když server zpracovává požadavek, se zpracovává zpracováním výjimek serveru. Vlastní chybové stránky aplikace, middleware pro zpracování výjimek a filtry toto chování neovlivní.
Ošetření výjimek při spuštění
Pouze vrstva hostování může zpracovávat výjimky, které probíhají při spuštění aplikace. Hostitel lze nakonfigurovat tak, aby zaznamenával chyby při spuštění a zaznamenával podrobné chyby.
Vrstva hostování může zobrazit chybovou stránku zachycené chyby při spuštění pouze v případě, že k chybě dojde po vazbě adresy hostitele nebo portu. Pokud se vazba nezdaří:
- Vrstva hostování zaznamená kritickou výjimku.
- Proces dotnet se chybově ukončí.
- Pokud je Kestrelserver HTTP, nezobrazí se žádná chybová stránka.
Pokud je proces spuštěný ve službě IIS (nebo ve službě Aplikace Azure) nebo IIS Express, vrátí modul ASP.NET Core chybu procesu 502.5. Další informace najdete v tématu Řešení potíží ASP.NET Core ve službě Aplikace Azure a službě IIS.
Chybová stránka databáze
Filtr AddDatabaseDeveloperPageExceptionFilter výjimek stránky pro vývojáře databáze zachycuje výjimky související s databází, které je možné vyřešit pomocí migrací Entity Framework Core. Pokud dojde k těmto výjimkám, vygeneruje se odpověď HTML s podrobnostmi o možných akcích k vyřešení problému. Tato stránka je povolená pouze ve vývojovém prostředí. Následující kód přidá filtr výjimek stránky pro vývojáře databáze:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Filtry výjimek
V aplikacích MVC je možné nakonfigurovat filtry výjimek globálně nebo podle kontroleru nebo podle akce. V Razor aplikacích Pages je možné je nakonfigurovat globálně nebo podle modelu stránky. Tyto filtry zpracovávají všechny neošetřené výjimky, ke kterým dochází během provádění akce kontroleru nebo jiného filtru. Další informace najdete v tématu Filtry v ASP.NET Core.
Filtry výjimek jsou užitečné pro zachycení výjimek, ke kterým dochází v rámci akcí MVC, ale nejsou tak flexibilní jako integrovaný middlewareUseExceptionHandler pro zpracování výjimek. Doporučujeme použít UseExceptionHandler
, pokud nepotřebujete provádět zpracování chyb odlišně podle toho, jakou akci MVC zvolíte.
Chyby stavu modelu
Informace o tom, jak zpracovávat chyby stavu modelu, naleznete v tématu Vazby modelu a Ověření modelu.
Podrobnosti o problému
Podrobnosti o problému nejsou jediným formátem odpovědi, který popisuje chybu rozhraní HTTP API, ale běžně se používají k hlášení chyb pro rozhraní HTTP API.
Služba podrobností problému implementuje IProblemDetailsService rozhraní, které podporuje vytváření podrobností o problému v ASP.NET Core. Metoda AddProblemDetails(IServiceCollection) rozšíření při IServiceCollection registraci výchozí IProblemDetailsService
implementace.
V aplikacích ASP.NET Core generuje následující middleware při zavolání podrobnosti o problému odpovědi AddProblemDetails
HTTP, s výjimkou případů, kdy Accept
hlavička HTTP požadavku neobsahuje jeden z typů obsahu podporovaných zaregistrovaným IProblemDetailsWriter (výchozí: application/json
):
- ExceptionHandlerMiddleware: Vygeneruje odpověď na podrobnosti o problému, pokud není definována vlastní obslužná rutina.
- StatusCodePagesMiddleware: Ve výchozím nastavení vygeneruje odpověď podrobností o problému.
- DeveloperExceptionPageMiddleware: Vygeneruje odpověď na podrobnosti o problému při vývoji, pokud hlavička
Accept
HTTP požadavku neobsahujetext/html
.
Následující kód nakonfiguruje aplikaci tak, aby vygenerovala odpověď na podrobnosti o problému pro všechny odpovědi na chyby klienta HTTP a serveru, které ještě nemají základní obsah:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
V další části se dozvíte, jak přizpůsobit text odpovědi s podrobnostmi o problému.
Přizpůsobení podrobností o problému
Automatické vytváření ProblemDetails
můžete přizpůsobit pomocí některé z následujících možností:
- Použití
ProblemDetailsOptions.CustomizeProblemDetails
- Použití vlastního
IProblemDetailsWriter
IProblemDetailsService
Volání v middlewaru
CustomizeProblemDetails
operace
Vygenerované podrobnosti o problému lze přizpůsobit pomocí CustomizeProblemDetailsa vlastní nastavení se použijí na všechny automaticky generované podrobnosti o problému.
Následující kód používá ProblemDetailsOptions k nastavení CustomizeProblemDetails:
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();
Výsledek koncového HTTP Status 400 Bad Request
bodu například vytvoří následující text odpovědi s podrobnostmi o problému:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Zvyk IProblemDetailsWriter
Pro IProblemDetailsWriter pokročilá přizpůsobení je možné vytvořit implementaci.
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));
}
}
Poznámka: Při použití vlastní IProblemDetailsWriter
, vlastní IProblemDetailsWriter
musí být registrován před voláním AddRazorPages, AddControllers, , AddControllersWithViewsnebo AddMvc:
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();
Podrobnosti o problému z middlewaru
Alternativním přístupem k použití s ProblemDetailsOptions CustomizeProblemDetails je nastavení v middlewaru ProblemDetails . Odpověď s podrobnostmi o problému může být napsána voláním IProblemDetailsService.WriteAsync
:
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();
V předchozím kódu minimální koncové body /divide
rozhraní API a /squareroot
vrátí očekávanou vlastní odpověď na problém při zadávání chyb.
Koncové body kontroleru rozhraní API vrací výchozí odpověď na problém při zadávání chyb, nikoli vlastní odpověď na problém. Výchozí odpověď na problém je vrácena, protože kontroler rozhraní API zapisoval do streamu odpovědi, podrobnosti o problému pro stavové kódy chyb, před IProblemDetailsService.WriteAsync
voláním a odpověď se znovu nezapíše .
Následující ValuesController
vrátí hodnotu BadRequestResult, která zapisuje do streamu odpovědi, a proto zabraňuje vrácení vlastní odpovědi na problém.
[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));
}
}
Následující Values3Controller
vrátí ControllerBase.Problem
výsledek očekávaného vlastního problému:
[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));
}
}
Vytvoření datové části ProblemDetails pro výjimky
Zvažte následující aplikaci:
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();
Pokud dojde k výjimce v prostředích, která nejsou vývojová, jedná se o standardní odpověď ProblemDetails, která se vrátí klientovi:
{
"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"
}
U většiny aplikací je předchozí kód vše, co je potřeba pro výjimky. Následující část ale ukazuje, jak získat podrobnější odpovědi na problémy.
Alternativou k vlastní stránce obslužné rutiny výjimky je poskytnutí lambda UseExceptionHandler. Použití lambda umožňuje přístup k chybě a napsání odpovědi s podrobnostmi o problému pomocí 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();
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
Alternativním přístupem k vygenerování podrobností o problému je použití balíčku NuGet jiného výrobce Hellang.Middleware.ProblemDetails , který lze použít k mapování výjimek a chyb klienta na podrobnosti o problému.
Další materiály
- Zobrazení nebo stažení ukázkového kódu (postup stažení)
- Řešení potíží s ASP.NET Core v Azure App Service a ve službě IIS
- Řešení běžných chyb v Azure App Service a ve službě IIS souvisejících s ASP.NET Core
- Zpracování chyb ve webových rozhraních API založených na řadiči jádra ASP.NET
- Zpracování chyb v minimálních rozhraních API
Od Tom Dykstra
Tento článek popisuje běžné přístupy ke zpracování chyb ve webových aplikacích ASP.NET Core. Podívejte se také na chyby v ASP.NET webových rozhraních API založených na jádru a zpracování chyb v minimálních rozhraních API.
Stránka výjimky pro vývojáře
Na stránce výjimka pro vývojáře se zobrazují podrobné informace o neošetřených výjimkách požadavků. ASP.NET aplikace Core ve výchozím nastavení povolí stránku výjimky pro vývojáře, pokud jsou obě:
- Běží ve vývojovém prostředí.
- Aplikace vytvořená s aktuálními šablonami, to znamená pomocí WebApplication.CreateBuilder. Aplikace vytvořené pomocí příkazu
WebHost.CreateDefaultBuilder
musí povolit stránku výjimky vývojáře volánímapp.UseDeveloperExceptionPage
Configure
.
Stránka výjimky vývojáře se spouští v rané fázi kanálu middlewaru, aby bylo možné zachytit neošetřené výjimky vyvolané v middlewaru, které následuje.
Podrobné informace o výjimce by se neměly zobrazovat veřejně při spuštění aplikace v produkčním prostředí. Další informace o konfiguraci prostředí najdete v tématu Použití více prostředí v ASP.NET Core.
Stránka výjimky pro vývojáře může obsahovat následující informace o výjimce a požadavku:
- Trasování zásobníku
- Parametry řetězce dotazu, pokud nějaké
- Soubory cookie, pokud nějaké
- Hlavičky
Na stránce výjimky pro vývojáře není zaručeno, že poskytnete žádné informace. Protokolování slouží k úplným informacím o chybě.
Stránka obslužné rutiny výjimky
Chcete-li nakonfigurovat vlastní stránku zpracování chyb pro produkční prostředí, zavolejte UseExceptionHandler. Tento middleware pro zpracování výjimek:
- Zachytává a zaznamenává neošetřené výjimky.
- Znovu spustí požadavek v alternativním kanálu pomocí uvedené cesty. Pokud se odpověď spustila, požadavek se znovu nespustí. Vygenerovaný kód šablony znovu spustí požadavek pomocí
/Error
cesty.
Upozorňující
Pokud alternativní kanál vyvolá výjimku vlastní, middleware zpracování výjimek znovu zvětšuje původní výjimku.
Vzhledem k tomu, že tento middleware může kanál požadavku znovu spustit:
- Middleware musí zpracovávat opakování se stejným požadavkem. Obvykle to znamená, že po zavolání
_next
nebo uložení zpracování do mezipamětiHttpContext
na zařízení, aby se zabránilo jeho opětovnému vytvoření. Při práci s textem požadavku to znamená ukládání do vyrovnávací paměti nebo ukládání výsledků do mezipaměti, jako je čtečka formulářů. - UseExceptionHandler(IApplicationBuilder, String) Pro přetížení, které se používá v šablonách, je změněna pouze cesta požadavku a směrovací data jsou vymazána. Všechna data požadavku, jako jsou hlavičky, metoda a položky, se znovu používají tak, jak jsou.
- Služby s vymezeným oborem zůstávají stejné.
V následujícím příkladu UseExceptionHandler přidá middleware pro zpracování výjimek v prostředích, která nejsou vývojová:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Šablona Razor aplikace Pages poskytuje ve složce Pages chybovou stránku (.cshtml
) a PageModel třídu (ErrorModel
). V případě aplikace MVC obsahuje šablona projektu metodu Error
akce a zobrazení Chyba kontroleru Home .
Middleware zpracování výjimek znovu spustí požadavek pomocí původní metody HTTP. Pokud je koncový bod obslužné rutiny chyby omezen na konkrétní sadu metod HTTP, spustí se pouze pro tyto metody HTTP. Například akce kontroleru MVC, která používá [HttpGet]
atribut, se spouští pouze pro požadavky GET. Abyste zajistili, že všechny požadavky dosáhnou vlastní stránky zpracování chyb, neomezovat je na konkrétní sadu metod HTTP.
Zpracování výjimek odlišně na základě původní metody HTTP:
- Pro Razor Stránky vytvořte více metod obslužné rutiny. Slouží
OnGet
například ke zpracování výjimek GET a zpracováníOnPost
výjimek POST. - Pro MVC použijte atributy příkazů HTTP na více akcí. Slouží
[HttpGet]
například ke zpracování výjimek GET a zpracování[HttpPost]
výjimek POST.
Pokud chcete umožnit neověřeným uživatelům zobrazit vlastní stránku pro zpracování chyb, ujistěte se, že podporuje anonymní přístup.
Přístup k výjimce
Slouží IExceptionHandlerPathFeature k přístupu k výjimce a původní cestě požadavku v obslužné rutině chyby. Následující příklad používá IExceptionHandlerPathFeature
k získání dalších informací o výjimce, která byla vyvolán:
[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.";
}
}
}
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
Lambda obslužné rutiny výjimek
Alternativou k vlastní stránce obslužné rutiny výjimky je poskytnutí lambda UseExceptionHandler. Použití lambda umožňuje přístup k chybě před vrácením odpovědi.
Následující kód používá lambda pro zpracování výjimek:
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();
}
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
UseStatusCodePages
Ve výchozím nastavení aplikace ASP.NET Core neposkytuje stavovou znakovou stránku pro stavové kódy chyb HTTP, například 404 – Nenalezena. Když aplikace nastaví stavový kód chyby HTTP 400-599, který nemá tělo, vrátí stavový kód a prázdný text odpovědi. Pokud chcete povolit výchozí obslužné rutiny jen pro text pro běžné stavové kódy chyb, zavolejte do UseStatusCodePages Program.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Před zpracováním middlewaru žádostí zavolejte UseStatusCodePages
. Například zavolejte UseStatusCodePages
před middlewarem statického souboru a middlewarem koncových bodů.
Pokud UseStatusCodePages
se nepoužívá, přechod na adresu URL bez koncového bodu vrátí chybovou zprávu závislá na prohlížeči, která značí, že se koncový bod nenašel. Při UseStatusCodePages
zavolání vrátí prohlížeč následující odpověď:
Status Code: 404; Not Found
UseStatusCodePages
se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
Poznámka:
Middleware stavových kódů nezachytává výjimky. Pokud chcete poskytnout vlastní stránku zpracování chyb, použijte stránku obslužné rutiny výjimky.
UseStatusCodePages s formátovacím řetězcem
Pokud chcete přizpůsobit typ obsahu odpovědi a text, použijte přetížení UseStatusCodePages , které přebírá typ obsahu a formátovací řetězec:
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}");
V předchozím kódu {0}
je zástupný symbol pro kód chyby.
UseStatusCodePages
formátovací řetězec se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
PoužitíStatusCodePages s lambda
Pokud chcete zadat vlastní zpracování chyb a kód pro zápis odpovědí, použijte přetížení UseStatusCodePages , které přebírá výraz lambda:
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
s lambda se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
UseStatusCodePagesWithRedirects
Metoda UseStatusCodePagesWithRedirects rozšíření:
- Odešle klientovi stavový kód 302 .
- Přesměruje klienta na koncový bod zpracování chyb zadaný v šabloně adresy URL. Koncový bod zpracování chyb obvykle zobrazuje informace o chybě a vrací http 200.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Šablona adresy URL může obsahovat {0}
zástupný symbol pro stavový kód, jak je znázorněno v předchozím kódu. Pokud šablona adresy URL začíná vlnovkou ~
, ~
nahradí se aplikací PathBase
. Při zadávání koncového bodu v aplikaci vytvořte zobrazení nebo Razor stránku MVC pro koncový bod.
Tato metoda se běžně používá v případě, že aplikace:
- Měl by přesměrovat klienta na jiný koncový bod, obvykle v případech, kdy jiná aplikace zpracovává chybu. U webových aplikací se adresní řádek prohlížeče klienta odráží přesměrovaný koncový bod.
- Nemělo by se zachovat a vrátit původní stavový kód s počáteční odpovědí přesměrování.
UseStatusCodePagesWithReExecute
Metoda UseStatusCodePagesWithReExecute rozšíření:
- Vygeneruje tělo odpovědi opětovným spuštěním kanálu požadavku pomocí alternativní cesty.
- Nezmění stavový kód před opětovným spuštěním kanálu ani po jeho opětovném spuštění.
Nové spuštění kanálu může změnit stavový kód odpovědi, protože nový kanál má plnou kontrolu nad stavovým kódem. Pokud nový kanál nezmění stavový kód, původní stavový kód se odešle klientovi.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Pokud je zadaný koncový bod v aplikaci, vytvořte zobrazení nebo Razor stránku MVC pro koncový bod.
Tato metoda se běžně používá, když by aplikace měla:
- Zpracujte požadavek bez přesměrování na jiný koncový bod. U webových aplikací se adresní řádek prohlížeče klienta odráží původně požadovaný koncový bod.
- Zachování a vrácení původního stavového kódu s odpovědí
Šablona adresy URL musí začínat /
a může obsahovat zástupný symbol {0}
pro stavový kód. Chcete-li předat stavový kód jako parametr řetězce dotazu, předejte druhý argument do UseStatusCodePagesWithReExecute
. Příklad:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Koncový bod, který chybu zpracuje, může získat původní adresu URL, která chybu vygenerovala, jak je znázorněno v následujícím příkladu:
[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}";
}
}
}
Vzhledem k tomu, že tento middleware může kanál požadavku znovu spustit:
- Middleware musí zpracovávat opakování se stejným požadavkem. Obvykle to znamená, že po zavolání
_next
nebo uložení zpracování do mezipamětiHttpContext
na zařízení, aby se zabránilo jeho opětovnému vytvoření. Při práci s textem požadavku to znamená ukládání do vyrovnávací paměti nebo ukládání výsledků do mezipaměti, jako je čtečka formulářů. - Služby s vymezeným oborem zůstávají stejné.
Zakázat stavové kódové stránky
Chcete-li zakázat stránky stavového kódu pro kontroler MVC nebo metodu akce, použijte atribut [SkipStatusCodePages].
Chcete-li zakázat stavové kódové stránky pro konkrétní požadavky v Razor metodě obslužné rutiny stránky nebo v kontroleru MVC, použijte IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kód pro zpracování výjimek
Kód na stránkách zpracování výjimek může také vyvolat výjimky. Produkční chybové stránky by se měly důkladně testovat a pečlivě se postarat, aby nedocházelo k výjimkám jejich vlastních.
Hlavičky odpovědi
Po odeslání hlaviček odpovědi:
- Aplikace nemůže změnit stavový kód odpovědi.
- Všechny stránky výjimek nebo obslužné rutiny se nedají spustit. Odpověď musí být dokončena nebo přerušeno připojení.
Zpracování výjimek serveru
Kromě logiky zpracování výjimek v aplikaci může implementace serveru HTTP zpracovávat některé výjimky. Pokud server zachytí výjimku před odesláním hlaviček odpovědi, server odešle 500 - Internal Server Error
odpověď bez textu odpovědi. Pokud server zachytí výjimku po odeslání hlaviček odpovědi, server připojení zavře. Požadavky, které aplikace nezpracuje, zpracovává server. Všechny výjimky, ke kterým dochází, když server zpracovává požadavek, se zpracovává zpracováním výjimek serveru. Vlastní chybové stránky aplikace, middleware pro zpracování výjimek a filtry toto chování neovlivní.
Ošetření výjimek při spuštění
Pouze vrstva hostování může zpracovávat výjimky, které probíhají při spuštění aplikace. Hostitel lze nakonfigurovat tak, aby zaznamenával chyby při spuštění a zaznamenával podrobné chyby.
Vrstva hostování může zobrazit chybovou stránku zachycené chyby při spuštění pouze v případě, že k chybě dojde po vazbě adresy hostitele nebo portu. Pokud se vazba nezdaří:
- Vrstva hostování zaznamená kritickou výjimku.
- Proces dotnet se chybově ukončí.
- Pokud je Kestrelserver HTTP, nezobrazí se žádná chybová stránka.
Pokud je proces spuštěný ve službě IIS (nebo ve službě Aplikace Azure) nebo IIS Express, vrátí modul ASP.NET Core chybu procesu 502.5. Další informace najdete v tématu Řešení potíží ASP.NET Core ve službě Aplikace Azure a službě IIS.
Chybová stránka databáze
Filtr AddDatabaseDeveloperPageExceptionFilter výjimek stránky pro vývojáře databáze zachycuje výjimky související s databází, které je možné vyřešit pomocí migrací Entity Framework Core. Pokud dojde k těmto výjimkám, vygeneruje se odpověď HTML s podrobnostmi o možných akcích k vyřešení problému. Tato stránka je povolená pouze ve vývojovém prostředí. Následující kód přidá filtr výjimek stránky pro vývojáře databáze:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Filtry výjimek
V aplikacích MVC je možné nakonfigurovat filtry výjimek globálně nebo podle kontroleru nebo podle akce. V Razor aplikacích Pages je možné je nakonfigurovat globálně nebo podle modelu stránky. Tyto filtry zpracovávají všechny neošetřené výjimky, ke kterým dochází během provádění akce kontroleru nebo jiného filtru. Další informace najdete v tématu Filtry v ASP.NET Core.
Filtry výjimek jsou užitečné pro zachycení výjimek, ke kterým dochází v rámci akcí MVC, ale nejsou tak flexibilní jako integrovaný middlewareUseExceptionHandler pro zpracování výjimek. Doporučujeme použít UseExceptionHandler
, pokud nepotřebujete provádět zpracování chyb odlišně podle toho, jakou akci MVC zvolíte.
Chyby stavu modelu
Informace o tom, jak zpracovávat chyby stavu modelu, naleznete v tématu Vazby modelu a Ověření modelu.
Podrobnosti o problému
Podrobnosti o problému nejsou jediným formátem odpovědi, který popisuje chybu rozhraní HTTP API, ale běžně se používají k hlášení chyb pro rozhraní HTTP API.
Služba podrobností problému implementuje IProblemDetailsService rozhraní, které podporuje vytváření podrobností o problému v ASP.NET Core. Metoda AddProblemDetails(IServiceCollection) rozšíření při IServiceCollection registraci výchozí IProblemDetailsService
implementace.
V aplikacích ASP.NET Core generuje následující middleware při zavolání podrobnosti o problému odpovědi AddProblemDetails
HTTP, s výjimkou případů, kdy Accept
hlavička HTTP požadavku neobsahuje jeden z typů obsahu podporovaných zaregistrovaným IProblemDetailsWriter (výchozí: application/json
):
- ExceptionHandlerMiddleware: Vygeneruje odpověď na podrobnosti o problému, pokud není definována vlastní obslužná rutina.
- StatusCodePagesMiddleware: Ve výchozím nastavení vygeneruje odpověď podrobností o problému.
- DeveloperExceptionPageMiddleware: Vygeneruje odpověď na podrobnosti o problému při vývoji, pokud hlavička
Accept
HTTP požadavku neobsahujetext/html
.
Následující kód nakonfiguruje aplikaci tak, aby vygenerovala odpověď na podrobnosti o problému pro všechny odpovědi na chyby klienta HTTP a serveru, které ještě nemají základní obsah:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
V další části se dozvíte, jak přizpůsobit text odpovědi s podrobnostmi o problému.
Přizpůsobení podrobností o problému
Automatické vytváření ProblemDetails
můžete přizpůsobit pomocí některé z následujících možností:
- Použití
ProblemDetailsOptions.CustomizeProblemDetails
- Použití vlastního
IProblemDetailsWriter
IProblemDetailsService
Volání v middlewaru
CustomizeProblemDetails
operace
Vygenerované podrobnosti o problému lze přizpůsobit pomocí CustomizeProblemDetailsa vlastní nastavení se použijí na všechny automaticky generované podrobnosti o problému.
Následující kód používá ProblemDetailsOptions k nastavení CustomizeProblemDetails:
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();
Výsledek koncového HTTP Status 400 Bad Request
bodu například vytvoří následující text odpovědi s podrobnostmi o problému:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Zvyk IProblemDetailsWriter
Pro IProblemDetailsWriter pokročilá přizpůsobení je možné vytvořit implementaci.
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));
}
}
Poznámka: Při použití vlastní IProblemDetailsWriter
, vlastní IProblemDetailsWriter
musí být registrován před voláním AddRazorPages, AddControllers, , AddControllersWithViewsnebo AddMvc:
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();
Podrobnosti o problému z middlewaru
Alternativním přístupem k použití s ProblemDetailsOptions CustomizeProblemDetails je nastavení v middlewaru ProblemDetails . Odpověď s podrobnostmi o problému může být napsána voláním IProblemDetailsService.WriteAsync
:
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();
V předchozím kódu minimální koncové body /divide
rozhraní API a /squareroot
vrátí očekávanou vlastní odpověď na problém při zadávání chyb.
Koncové body kontroleru rozhraní API vrací výchozí odpověď na problém při zadávání chyb, nikoli vlastní odpověď na problém. Výchozí odpověď na problém je vrácena, protože kontroler rozhraní API zapisoval do streamu odpovědi, podrobnosti o problému pro stavové kódy chyb, před IProblemDetailsService.WriteAsync
voláním a odpověď se znovu nezapíše .
Následující ValuesController
vrátí hodnotu BadRequestResult, která zapisuje do streamu odpovědi, a proto zabraňuje vrácení vlastní odpovědi na problém.
[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));
}
}
Následující Values3Controller
vrátí ControllerBase.Problem
výsledek očekávaného vlastního problému:
[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));
}
}
Vytvoření datové části ProblemDetails pro výjimky
Zvažte následující aplikaci:
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();
Pokud dojde k výjimce v prostředích, která nejsou vývojová, jedná se o standardní odpověď ProblemDetails, která se vrátí klientovi:
{
"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"
}
U většiny aplikací je předchozí kód vše, co je potřeba pro výjimky. Následující část ale ukazuje, jak získat podrobnější odpovědi na problémy.
Alternativou k vlastní stránce obslužné rutiny výjimky je poskytnutí lambda UseExceptionHandler. Použití lambda umožňuje přístup k chybě a napsání odpovědi s podrobnostmi o problému pomocí 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();
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
Alternativním přístupem k vygenerování podrobností o problému je použití balíčku NuGet jiného výrobce Hellang.Middleware.ProblemDetails , který lze použít k mapování výjimek a chyb klienta na podrobnosti o problému.
Další materiály
Od Tom Dykstra
Tento článek popisuje běžné přístupy ke zpracování chyb ve webových aplikacích ASP.NET Core. Viz Zpracování chyb ve webových rozhraních API založených na řadiči ASP.NET Core pro webová rozhraní API.
Stránka výjimky pro vývojáře
Na stránce výjimka pro vývojáře se zobrazují podrobné informace o neošetřených výjimkách požadavků. ASP.NET aplikace Core ve výchozím nastavení povolí stránku výjimky pro vývojáře, pokud jsou obě:
- Běží ve vývojovém prostředí.
- Aplikace vytvořená s aktuálními šablonami, to znamená pomocí WebApplication.CreateBuilder. Aplikace vytvořené pomocí příkazu
WebHost.CreateDefaultBuilder
musí povolit stránku výjimky vývojáře volánímapp.UseDeveloperExceptionPage
Configure
.
Stránka výjimky vývojáře se spouští v rané fázi kanálu middlewaru, aby bylo možné zachytit neošetřené výjimky vyvolané v middlewaru, které následuje.
Podrobné informace o výjimce by se neměly zobrazovat veřejně při spuštění aplikace v produkčním prostředí. Další informace o konfiguraci prostředí najdete v tématu Použití více prostředí v ASP.NET Core.
Stránka výjimky pro vývojáře může obsahovat následující informace o výjimce a požadavku:
- Trasování zásobníku
- Parametry řetězce dotazu, pokud nějaké
- Soubory cookie, pokud nějaké
- Hlavičky
Na stránce výjimky pro vývojáře není zaručeno, že poskytnete žádné informace. Protokolování slouží k úplným informacím o chybě.
Stránka obslužné rutiny výjimky
Chcete-li nakonfigurovat vlastní stránku zpracování chyb pro produkční prostředí, zavolejte UseExceptionHandler. Tento middleware pro zpracování výjimek:
- Zachytává a zaznamenává neošetřené výjimky.
- Znovu spustí požadavek v alternativním kanálu pomocí uvedené cesty. Pokud se odpověď spustila, požadavek se znovu nespustí. Vygenerovaný kód šablony znovu spustí požadavek pomocí
/Error
cesty.
Upozorňující
Pokud alternativní kanál vyvolá výjimku vlastní, middleware zpracování výjimek znovu zvětšuje původní výjimku.
V následujícím příkladu UseExceptionHandler přidá middleware pro zpracování výjimek v prostředích, která nejsou vývojová:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Šablona Razor aplikace Pages poskytuje ve složce Pages chybovou stránku (.cshtml
) a PageModel třídu (ErrorModel
). V případě aplikace MVC obsahuje šablona projektu metodu Error
akce a zobrazení Chyba kontroleru Home .
Middleware zpracování výjimek znovu spustí požadavek pomocí původní metody HTTP. Pokud je koncový bod obslužné rutiny chyby omezen na konkrétní sadu metod HTTP, spustí se pouze pro tyto metody HTTP. Například akce kontroleru MVC, která používá [HttpGet]
atribut, se spouští pouze pro požadavky GET. Abyste zajistili, že všechny požadavky dosáhnou vlastní stránky zpracování chyb, neomezovat je na konkrétní sadu metod HTTP.
Zpracování výjimek odlišně na základě původní metody HTTP:
- Pro Razor Stránky vytvořte více metod obslužné rutiny. Slouží
OnGet
například ke zpracování výjimek GET a zpracováníOnPost
výjimek POST. - Pro MVC použijte atributy příkazů HTTP na více akcí. Slouží
[HttpGet]
například ke zpracování výjimek GET a zpracování[HttpPost]
výjimek POST.
Pokud chcete umožnit neověřeným uživatelům zobrazit vlastní stránku pro zpracování chyb, ujistěte se, že podporuje anonymní přístup.
Přístup k výjimce
Slouží IExceptionHandlerPathFeature k přístupu k výjimce a původní cestě požadavku v obslužné rutině chyby. Následující příklad používá IExceptionHandlerPathFeature
k získání dalších informací o výjimce, která byla vyvolán:
[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.";
}
}
}
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
Lambda obslužné rutiny výjimek
Alternativou k vlastní stránce obslužné rutiny výjimky je poskytnutí lambda UseExceptionHandler. Použití lambda umožňuje přístup k chybě před vrácením odpovědi.
Následující kód používá lambda pro zpracování výjimek:
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();
}
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
UseStatusCodePages
Ve výchozím nastavení aplikace ASP.NET Core neposkytuje stavovou znakovou stránku pro stavové kódy chyb HTTP, například 404 – Nenalezena. Když aplikace nastaví stavový kód chyby HTTP 400-599, který nemá tělo, vrátí stavový kód a prázdný text odpovědi. Pokud chcete povolit výchozí obslužné rutiny jen pro text pro běžné stavové kódy chyb, zavolejte do UseStatusCodePages Program.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Před zpracováním middlewaru žádostí zavolejte UseStatusCodePages
. Například zavolejte UseStatusCodePages
před middlewarem statického souboru a middlewarem koncových bodů.
Pokud UseStatusCodePages
se nepoužívá, přechod na adresu URL bez koncového bodu vrátí chybovou zprávu závislá na prohlížeči, která značí, že se koncový bod nenašel. Při UseStatusCodePages
zavolání vrátí prohlížeč následující odpověď:
Status Code: 404; Not Found
UseStatusCodePages
se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
Poznámka:
Middleware stavových kódů nezachytává výjimky. Pokud chcete poskytnout vlastní stránku zpracování chyb, použijte stránku obslužné rutiny výjimky.
UseStatusCodePages s formátovacím řetězcem
Pokud chcete přizpůsobit typ obsahu odpovědi a text, použijte přetížení UseStatusCodePages , které přebírá typ obsahu a formátovací řetězec:
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}");
V předchozím kódu {0}
je zástupný symbol pro kód chyby.
UseStatusCodePages
formátovací řetězec se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
PoužitíStatusCodePages s lambda
Pokud chcete zadat vlastní zpracování chyb a kód pro zápis odpovědí, použijte přetížení UseStatusCodePages , které přebírá výraz lambda:
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
s lambda se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
UseStatusCodePagesWithRedirects
Metoda UseStatusCodePagesWithRedirects rozšíření:
- Odešle klientovi stavový kód 302 .
- Přesměruje klienta na koncový bod zpracování chyb zadaný v šabloně adresy URL. Koncový bod zpracování chyb obvykle zobrazuje informace o chybě a vrací http 200.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Šablona adresy URL může obsahovat {0}
zástupný symbol pro stavový kód, jak je znázorněno v předchozím kódu. Pokud šablona adresy URL začíná vlnovkou ~
, ~
nahradí se aplikací PathBase
. Při zadávání koncového bodu v aplikaci vytvořte zobrazení nebo Razor stránku MVC pro koncový bod.
Tato metoda se běžně používá v případě, že aplikace:
- Měl by přesměrovat klienta na jiný koncový bod, obvykle v případech, kdy jiná aplikace zpracovává chybu. U webových aplikací se adresní řádek prohlížeče klienta odráží přesměrovaný koncový bod.
- Nemělo by se zachovat a vrátit původní stavový kód s počáteční odpovědí přesměrování.
UseStatusCodePagesWithReExecute
Metoda UseStatusCodePagesWithReExecute rozšíření:
- Vrátí původní stavový kód klientovi.
- Vygeneruje tělo odpovědi opětovným spuštěním kanálu požadavku pomocí alternativní cesty.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Pokud je zadaný koncový bod v aplikaci, vytvořte zobrazení nebo Razor stránku MVC pro koncový bod.
Tato metoda se běžně používá, když by aplikace měla:
- Zpracujte požadavek bez přesměrování na jiný koncový bod. U webových aplikací se adresní řádek prohlížeče klienta odráží původně požadovaný koncový bod.
- Zachování a vrácení původního stavového kódu s odpovědí
Šablona adresy URL musí začínat /
a může obsahovat zástupný symbol {0}
pro stavový kód. Chcete-li předat stavový kód jako parametr řetězce dotazu, předejte druhý argument do UseStatusCodePagesWithReExecute
. Příklad:
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
Koncový bod, který chybu zpracuje, může získat původní adresu URL, která chybu vygenerovala, jak je znázorněno v následujícím příkladu:
[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);
}
}
}
Zakázat stavové kódové stránky
Chcete-li zakázat stránky stavového kódu pro kontroler MVC nebo metodu akce, použijte atribut [SkipStatusCodePages].
Chcete-li zakázat stavové kódové stránky pro konkrétní požadavky v Razor metodě obslužné rutiny stránky nebo v kontroleru MVC, použijte IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kód pro zpracování výjimek
Kód na stránkách zpracování výjimek může také vyvolat výjimky. Produkční chybové stránky by se měly důkladně testovat a pečlivě se postarat, aby nedocházelo k výjimkám jejich vlastních.
Hlavičky odpovědi
Po odeslání hlaviček odpovědi:
- Aplikace nemůže změnit stavový kód odpovědi.
- Všechny stránky výjimek nebo obslužné rutiny se nedají spustit. Odpověď musí být dokončena nebo přerušeno připojení.
Zpracování výjimek serveru
Kromě logiky zpracování výjimek v aplikaci může implementace serveru HTTP zpracovávat některé výjimky. Pokud server zachytí výjimku před odesláním hlaviček odpovědi, server odešle 500 - Internal Server Error
odpověď bez textu odpovědi. Pokud server zachytí výjimku po odeslání hlaviček odpovědi, server připojení zavře. Požadavky, které aplikace nezpracuje, zpracovává server. Všechny výjimky, ke kterým dochází, když server zpracovává požadavek, se zpracovává zpracováním výjimek serveru. Vlastní chybové stránky aplikace, middleware pro zpracování výjimek a filtry toto chování neovlivní.
Ošetření výjimek při spuštění
Pouze vrstva hostování může zpracovávat výjimky, které probíhají při spuštění aplikace. Hostitel lze nakonfigurovat tak, aby zaznamenával chyby při spuštění a zaznamenával podrobné chyby.
Vrstva hostování může zobrazit chybovou stránku zachycené chyby při spuštění pouze v případě, že k chybě dojde po vazbě adresy hostitele nebo portu. Pokud se vazba nezdaří:
- Vrstva hostování zaznamená kritickou výjimku.
- Proces dotnet se chybově ukončí.
- Pokud je Kestrelserver HTTP, nezobrazí se žádná chybová stránka.
Pokud je proces spuštěný ve službě IIS (nebo ve službě Aplikace Azure) nebo IIS Express, vrátí modul ASP.NET Core chybu procesu 502.5. Další informace najdete v tématu Řešení potíží ASP.NET Core ve službě Aplikace Azure a službě IIS.
Chybová stránka databáze
Filtr AddDatabaseDeveloperPageExceptionFilter výjimek stránky pro vývojáře databáze zachycuje výjimky související s databází, které je možné vyřešit pomocí migrací Entity Framework Core. Pokud dojde k těmto výjimkám, vygeneruje se odpověď HTML s podrobnostmi o možných akcích k vyřešení problému. Tato stránka je povolená pouze ve vývojovém prostředí. Následující kód přidá filtr výjimek stránky pro vývojáře databáze:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Filtry výjimek
V aplikacích MVC je možné nakonfigurovat filtry výjimek globálně nebo podle kontroleru nebo podle akce. V Razor aplikacích Pages je možné je nakonfigurovat globálně nebo podle modelu stránky. Tyto filtry zpracovávají všechny neošetřené výjimky, ke kterým dochází během provádění akce kontroleru nebo jiného filtru. Další informace najdete v tématu Filtry v ASP.NET Core.
Filtry výjimek jsou užitečné pro zachycení výjimek, ke kterým dochází v rámci akcí MVC, ale nejsou tak flexibilní jako integrovaný middlewareUseExceptionHandler pro zpracování výjimek. Doporučujeme použít UseExceptionHandler
, pokud nepotřebujete provádět zpracování chyb odlišně podle toho, jakou akci MVC zvolíte.
Chyby stavu modelu
Informace o tom, jak zpracovávat chyby stavu modelu, naleznete v tématu Vazby modelu a Ověření modelu.
Další materiály
Kirk Larkin, Tom Dykstra a Steve Smith
Tento článek popisuje běžné přístupy ke zpracování chyb ve webových aplikacích ASP.NET Core. Viz Zpracování chyb ve webových rozhraních API založených na řadiči ASP.NET Core pro webová rozhraní API.
Zobrazení nebo stažení vzorového kódu (Jak stáhnout.) Karta Síť na vývojářských nástrojích prohlížeče F12 je užitečná při testování ukázkové aplikace.
Stránka výjimky pro vývojáře
Na stránce výjimka pro vývojáře se zobrazují podrobné informace o neošetřených výjimkách požadavků. Šablony ASP.NET Core generují následující kód:
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();
});
}
Předchozí zvýrazněný kód povolí stránku výjimky vývojáře, když je aplikace spuštěná ve vývojovém prostředí.
Šablony jsou v UseDeveloperExceptionPage rané fázi kanálu middlewaru, aby mohly zachytit neošetřené výjimky vyvolané v middlewaru, které následuje.
Předchozí kód povolí stránku výjimky vývojáře pouze v době, kdy aplikace běží ve vývojovém prostředí. Podrobné informace o výjimce by se neměly zobrazovat veřejně při spuštění aplikace v produkčním prostředí. Další informace o konfiguraci prostředí najdete v tématu Použití více prostředí v ASP.NET Core.
Stránka výjimky pro vývojáře může obsahovat následující informace o výjimce a požadavku:
- Trasování zásobníku
- Parametry řetězce dotazu, pokud nějaké
- Soubory cookie, pokud nějaké
- Hlavičky
Na stránce výjimky pro vývojáře není zaručeno, že poskytnete žádné informace. Protokolování slouží k úplným informacím o chybě.
Stránka obslužné rutiny výjimky
Chcete-li nakonfigurovat vlastní stránku zpracování chyb pro produkční prostředí, zavolejte UseExceptionHandler. Tento middleware pro zpracování výjimek:
- Zachytává a zaznamenává neošetřené výjimky.
- Znovu spustí požadavek v alternativním kanálu pomocí uvedené cesty. Pokud se odpověď spustila, požadavek se znovu nespustí. Vygenerovaný kód šablony znovu spustí požadavek pomocí
/Error
cesty.
Upozorňující
Pokud alternativní kanál vyvolá výjimku vlastní, middleware zpracování výjimek znovu zvětšuje původní výjimku.
V následujícím příkladu UseExceptionHandler přidá middleware pro zpracování výjimek v prostředích, která nejsou vývojová:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Šablona Razor aplikace Pages poskytuje ve složce Pages chybovou stránku (.cshtml
) a PageModel třídu (ErrorModel
). V případě aplikace MVC obsahuje šablona projektu metodu Error
akce a zobrazení Chyba kontroleru Home .
Middleware zpracování výjimek znovu spustí požadavek pomocí původní metody HTTP. Pokud je koncový bod obslužné rutiny chyby omezen na konkrétní sadu metod HTTP, spustí se pouze pro tyto metody HTTP. Například akce kontroleru MVC, která používá [HttpGet]
atribut, se spouští pouze pro požadavky GET. Abyste zajistili, že všechny požadavky dosáhnou vlastní stránky zpracování chyb, neomezovat je na konkrétní sadu metod HTTP.
Zpracování výjimek odlišně na základě původní metody HTTP:
- Pro Razor Stránky vytvořte více metod obslužné rutiny. Slouží
OnGet
například ke zpracování výjimek GET a zpracováníOnPost
výjimek POST. - Pro MVC použijte atributy příkazů HTTP na více akcí. Slouží
[HttpGet]
například ke zpracování výjimek GET a zpracování[HttpPost]
výjimek POST.
Pokud chcete umožnit neověřeným uživatelům zobrazit vlastní stránku pro zpracování chyb, ujistěte se, že podporuje anonymní přístup.
Přístup k výjimce
Slouží IExceptionHandlerPathFeature k přístupu k výjimce a původní cestě požadavku v obslužné rutině chyby. Následující kód se přidá ExceptionMessage
do výchozího vygenerovaného Pages/Error.cshtml.cs
šablonami ASP.NET Core:
[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";
}
}
}
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
Otestování výjimky v ukázkové aplikaci:
- Nastavte prostředí na produkční.
- Odeberte komentáře ze
webBuilder.UseStartup<Startup>();
souboru .Program.cs
- Na stránce vyberte Aktivovat výjimkuhome.
Lambda obslužné rutiny výjimek
Alternativou k vlastní stránce obslužné rutiny výjimky je poskytnutí lambda UseExceptionHandler. Použití lambda umožňuje přístup k chybě před vrácením odpovědi.
Následující kód používá lambda pro zpracování výjimek:
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();
});
}
Upozorňující
Neslouží citlivým informacím o chybách od IExceptionHandlerFeature klientů nebo IExceptionHandlerPathFeature klientům. Obsluha chyb představuje bezpečnostní riziko.
Otestování výrazu lambda zpracování výjimek v ukázkové aplikaci:
- Nastavte prostředí na produkční.
- Odeberte komentáře ze
webBuilder.UseStartup<StartupLambda>();
souboru .Program.cs
- Na stránce vyberte Aktivovat výjimkuhome.
UseStatusCodePages
Ve výchozím nastavení aplikace ASP.NET Core neposkytuje stavovou znakovou stránku pro stavové kódy chyb HTTP, například 404 – Nenalezena. Když aplikace nastaví stavový kód chyby HTTP 400-599, který nemá tělo, vrátí stavový kód a prázdný text odpovědi. Pokud chcete zadat stavové kódové stránky, použijte middleware stavových stránek kódu. Pokud chcete povolit výchozí obslužné rutiny jen pro text pro běžné stavové kódy chyb, zavolejte UseStatusCodePages v Startup.Configure
metodě:
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();
});
}
Před zpracováním middlewaru žádostí zavolejte UseStatusCodePages
. Například zavolejte UseStatusCodePages
před middlewarem statického souboru a middlewarem koncových bodů.
Pokud UseStatusCodePages
se nepoužívá, přechod na adresu URL bez koncového bodu vrátí chybovou zprávu závislá na prohlížeči, která značí, že se koncový bod nenašel. Například přechod na Home/Privacy2
. Při UseStatusCodePages
zavolání prohlížeč vrátí:
Status Code: 404; Not Found
UseStatusCodePages
se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
UseStatusCodePages
Testování v ukázkové aplikaci:
- Nastavte prostředí na produkční.
- Odeberte komentáře ze
webBuilder.UseStartup<StartupUseStatusCodePages>();
souboru .Program.cs
- Vyberte odkazy na home stránce na home stránce.
Poznámka:
Middleware stavových kódů nezachytává výjimky. Pokud chcete poskytnout vlastní stránku zpracování chyb, použijte stránku obslužné rutiny výjimky.
UseStatusCodePages s formátovacím řetězcem
Pokud chcete přizpůsobit typ obsahu odpovědi a text, použijte přetížení UseStatusCodePages , které přebírá typ obsahu a formátovací řetězec:
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();
});
}
V předchozím kódu {0}
je zástupný symbol pro kód chyby.
UseStatusCodePages
formátovací řetězec se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
Pokud chcete testovat UseStatusCodePages
v ukázkové aplikaci, odeberte komentáře z webBuilder.UseStartup<StartupFormat>();
Program.cs
aplikace .
PoužitíStatusCodePages s lambda
Pokud chcete zadat vlastní zpracování chyb a kód pro zápis odpovědí, použijte přetížení UseStatusCodePages , které přebírá výraz lambda:
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
s lambda se obvykle nepoužívá v produkčním prostředí, protože vrací zprávu, která není pro uživatele užitečná.
Pokud chcete testovat UseStatusCodePages
v ukázkové aplikaci, odeberte komentáře z webBuilder.UseStartup<StartupStatusLambda>();
Program.cs
aplikace .
UseStatusCodePagesWithRedirects
Metoda UseStatusCodePagesWithRedirects rozšíření:
- Odešle klientovi stavový kód 302 .
- Přesměruje klienta na koncový bod zpracování chyb zadaný v šabloně adresy URL. Koncový bod zpracování chyb obvykle zobrazuje informace o chybě a vrací http 200.
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();
});
}
Šablona adresy URL může obsahovat {0}
zástupný symbol pro stavový kód, jak je znázorněno v předchozím kódu. Pokud šablona adresy URL začíná vlnovkou ~
, ~
nahradí se aplikací PathBase
. Při zadávání koncového bodu v aplikaci vytvořte zobrazení nebo Razor stránku MVC pro koncový bod. Razor Příklad stránky naleznete v části Pages/MyStatusCode.cshtml v ukázkové aplikaci.
Tato metoda se běžně používá v případě, že aplikace:
- Měl by přesměrovat klienta na jiný koncový bod, obvykle v případech, kdy jiná aplikace zpracovává chybu. U webových aplikací se adresní řádek prohlížeče klienta odráží přesměrovaný koncový bod.
- Nemělo by se zachovat a vrátit původní stavový kód s počáteční odpovědí přesměrování.
Pokud chcete testovat UseStatusCodePages
v ukázkové aplikaci, odeberte komentáře z webBuilder.UseStartup<StartupSCredirect>();
Program.cs
aplikace .
UseStatusCodePagesWithReExecute
Metoda UseStatusCodePagesWithReExecute rozšíření:
- Vrátí původní stavový kód klientovi.
- Vygeneruje tělo odpovědi opětovným spuštěním kanálu požadavku pomocí alternativní cesty.
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();
});
}
Pokud je zadaný koncový bod v aplikaci, vytvořte zobrazení nebo Razor stránku MVC pro koncový bod. Ujistěte se UseStatusCodePagesWithReExecute
, že je před umístěním UseRouting
požadavku možné směrovat na stavovou stránku. Razor Příklad stránky naleznete v části Pages/MyStatusCode2.cshtml v ukázkové aplikaci.
Tato metoda se běžně používá, když by aplikace měla:
- Zpracujte požadavek bez přesměrování na jiný koncový bod. U webových aplikací se adresní řádek prohlížeče klienta odráží původně požadovaný koncový bod.
- Zachování a vrácení původního stavového kódu s odpovědí
Šablony adres URL a řetězce dotazu můžou obsahovat zástupný symbol {0}
stavového kódu. Šablona adresy URL musí začínat /
na .
Koncový bod, který chybu zpracuje, může získat původní adresu URL, která chybu vygenerovala, jak je znázorněno v následujícím příkladu:
[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;
}
}
}
Razor Příklad stránky naleznete v části Pages/MyStatusCode2.cshtml v ukázkové aplikaci.
Pokud chcete testovat UseStatusCodePages
v ukázkové aplikaci, odeberte komentáře z webBuilder.UseStartup<StartupSCreX>();
Program.cs
aplikace .
Zakázat stavové kódové stránky
Chcete-li zakázat stránky stavového kódu pro kontroler MVC nebo metodu akce, použijte atribut [SkipStatusCodePages].
Chcete-li zakázat stavové kódové stránky pro konkrétní požadavky v Razor metodě obslužné rutiny stránky nebo v kontroleru MVC, použijte IStatusCodePagesFeature:
public void OnGet()
{
// using Microsoft.AspNetCore.Diagnostics;
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kód pro zpracování výjimek
Kód na stránkách zpracování výjimek může také vyvolat výjimky. Produkční chybové stránky by se měly důkladně testovat a pečlivě se postarat, aby nedocházelo k výjimkám jejich vlastních.
Hlavičky odpovědi
Po odeslání hlaviček odpovědi:
- Aplikace nemůže změnit stavový kód odpovědi.
- Všechny stránky výjimek nebo obslužné rutiny se nedají spustit. Odpověď musí být dokončena nebo přerušeno připojení.
Zpracování výjimek serveru
Kromě logiky zpracování výjimek v aplikaci může implementace serveru HTTP zpracovávat některé výjimky. Pokud server zachytí výjimku před odesláním hlaviček odpovědi, server odešle 500 - Internal Server Error
odpověď bez textu odpovědi. Pokud server zachytí výjimku po odeslání hlaviček odpovědi, server připojení zavře. Požadavky, které aplikace nezpracuje, zpracovává server. Všechny výjimky, ke kterým dochází, když server zpracovává požadavek, se zpracovává zpracováním výjimek serveru. Vlastní chybové stránky aplikace, middleware pro zpracování výjimek a filtry toto chování neovlivní.
Ošetření výjimek při spuštění
Pouze vrstva hostování může zpracovávat výjimky, které probíhají při spuštění aplikace. Hostitel lze nakonfigurovat tak, aby zaznamenával chyby při spuštění a zaznamenával podrobné chyby.
Vrstva hostování může zobrazit chybovou stránku zachycené chyby při spuštění pouze v případě, že k chybě dojde po vazbě adresy hostitele nebo portu. Pokud se vazba nezdaří:
- Vrstva hostování zaznamená kritickou výjimku.
- Proces dotnet se chybově ukončí.
- Pokud je Kestrelserver HTTP, nezobrazí se žádná chybová stránka.
Pokud je proces spuštěný ve službě IIS (nebo ve službě Aplikace Azure) nebo IIS Express, vrátí modul ASP.NET Core chybu procesu 502.5. Další informace najdete v tématu Řešení potíží ASP.NET Core ve službě Aplikace Azure a službě IIS.
Chybová stránka databáze
Filtr AddDatabaseDeveloperPageExceptionFilter
výjimek stránky pro vývojáře databáze zachycuje výjimky související s databází, které je možné vyřešit pomocí migrací Entity Framework Core. Pokud dojde k těmto výjimkám, vygeneruje se odpověď HTML s podrobnostmi o možných akcích k vyřešení problému. Tato stránka je povolená pouze ve vývojovém prostředí. Následující kód vygeneroval šablony ASP.NET Core Razor Pages při zadání jednotlivých uživatelských účtů:
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();
}
Filtry výjimek
V aplikacích MVC je možné nakonfigurovat filtry výjimek globálně nebo podle kontroleru nebo podle akce. V Razor aplikacích Pages je možné je nakonfigurovat globálně nebo podle modelu stránky. Tyto filtry zpracovávají všechny neošetřené výjimky, ke kterým dochází během provádění akce kontroleru nebo jiného filtru. Další informace najdete v tématu Filtry v ASP.NET Core.
Filtry výjimek jsou užitečné pro zachycení výjimek, ke kterým dochází v rámci akcí MVC, ale nejsou tak flexibilní jako integrovaný middlewareUseExceptionHandler
pro zpracování výjimek. Doporučujeme použít UseExceptionHandler
, pokud nepotřebujete provádět zpracování chyb odlišně podle toho, jakou akci MVC zvolíte.
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();
});
}
Chyby stavu modelu
Informace o tom, jak zpracovávat chyby stavu modelu, naleznete v tématu Vazby modelu a Ověření modelu.
Další materiály
Tom Dykstra a Steve Smith
Tento článek popisuje běžné přístupy ke zpracování chyb ve webových aplikacích ASP.NET Core. Viz Zpracování chyb ve webových rozhraních API založených na řadiči ASP.NET Core pro webová rozhraní API.
Zobrazení nebo stažení vzorového kódu (Jak stáhnout.)
Stránka výjimky pro vývojáře
Na stránce výjimka pro vývojáře se zobrazují podrobné informace o výjimkách požadavků. Šablony ASP.NET Core generují následující kód:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Předchozí kód povolí stránku výjimky vývojáře, když je aplikace spuštěná ve vývojovém prostředí.
Šablony jsou před jakýmkoli middlewarem, UseDeveloperExceptionPage takže výjimky jsou zachyceny v middlewaru, který následuje.
Předchozí kód povolí stránku výjimky vývojáře pouze v případech, kdy je aplikace spuštěná ve vývojovém prostředí. Podrobné informace o výjimce by se neměly zobrazovat veřejně při spuštění aplikace v produkčním prostředí. Další informace o konfiguraci prostředí najdete v tématu Použití více prostředí v ASP.NET Core.
Stránka výjimky pro vývojáře obsahuje následující informace o výjimce a požadavku:
- Trasování zásobníku
- Parametry řetězce dotazu, pokud nějaké
- Soubory cookie, pokud nějaké
- Hlavičky
Stránka obslužné rutiny výjimky
Ke konfiguraci vlastní stránky zpracování chyb pro produkční prostředí použijte middleware zpracování výjimek. Middleware:
- Zachytává a protokoluje výjimky.
- Znovu spustí požadavek v alternativním kanálu pro stránku nebo kontroler označený. Pokud se odpověď spustila, požadavek se znovu nespustí. Šablona vygenerovaný kód znovu spustí požadavek na
/Error
.
V následujícím příkladu přidá middleware zpracování výjimek v prostředích, UseExceptionHandler která nejsou vývojová:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Šablona Razor aplikace Pages poskytuje ve složce Pages chybovou stránku (.cshtml
) a PageModel třídu (ErrorModel
). V případě aplikace MVC obsahuje šablona projektu metodu akce Chyba a zobrazení Chyba v Home kontroleru.
Neoznačí metodu akce obslužné rutiny chyby s atributy metody HTTP, například HttpGet
. Explicitní příkazy brání některým požadavkům v dosažení metody. Pokud by se neověřeným uživatelům mělo zobrazit zobrazení chyb, povolte anonymní přístup k metodě.
Přístup k výjimce
Slouží IExceptionHandlerPathFeature k přístupu k výjimce a původní cestě požadavku v kontroleru nebo stránce obslužné rutiny chyby:
[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";
}
}
}
Upozorňující
Neservírujte klientům citlivé informace o chybách. Obsluha chyb představuje bezpečnostní riziko.
Pokud chcete aktivovat předchozí stránku zpracování výjimek, nastavte prostředí na produkční prostředí a vynuťte výjimku.
Lambda obslužné rutiny výjimek
Alternativou k vlastní stránce obslužné rutiny výjimky je poskytnutí lambda UseExceptionHandler. Použití lambda umožňuje přístup k chybě před vrácením odpovědi.
Tady je příklad použití lambda pro zpracování výjimek:
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();
}
V předchozím kódu se přidá, await context.Response.WriteAsync(new string(' ', 512));
aby prohlížeč Internet Explorer zobrazoval chybovou zprávu místo chybové zprávy IE. Další informace najdete u tohoto problému na GitHubu.
Upozorňující
Neslouží citlivým informacím o chybách od IExceptionHandlerFeature klientů nebo IExceptionHandlerPathFeature klientům. Obsluha chyb představuje bezpečnostní riziko.
Pokud chcete zobrazit výsledek zpracování výjimek lambda v ukázkové aplikaci, použijte ProdEnvironment
direktivy preprocesoru a ErrorHandlerLambda
vyberte Na stránce aktivovat výjimkuhome.
UseStatusCodePages
Ve výchozím nastavení aplikace ASP.NET Core neposkytuje stavovou stránku stavových kódů HTTP, například 404 – Nenalezena. Aplikace vrátí stavový kód a prázdný text odpovědi. Pokud chcete zadat stavové kódové stránky, použijte middleware Stavové stránky kódu.
Middleware je zpřístupněn balíčkem Microsoft.AspNetCore.Diagnostics .
Pokud chcete povolit výchozí obslužné rutiny jen pro text pro běžné stavové kódy chyb, zavolejte UseStatusCodePages v Startup.Configure
metodě:
app.UseStatusCodePages();
Před zpracováním požadavků volejte UseStatusCodePages
middleware (například Middleware statického souboru a middleware MVC).
Pokud UseStatusCodePages
se nepoužívá, přechod na adresu URL bez koncového bodu vrátí chybovou zprávu závislé na prohlížeči, která značí, že se koncový bod nenašel. Například přechod na Home/Privacy2
. Při UseStatusCodePages
zavolání prohlížeč vrátí:
Status Code: 404; Not Found
UseStatusCodePages s formátovacím řetězcem
Pokud chcete přizpůsobit typ obsahu odpovědi a text, použijte přetížení UseStatusCodePages , které přebírá typ obsahu a formátovací řetězec:
app.UseStatusCodePages(
"text/plain", "Status code page, status code: {0}");
PoužitíStatusCodePages s lambda
Pokud chcete zadat vlastní zpracování chyb a kód pro zápis odpovědí, použijte přetížení UseStatusCodePages , které přebírá výraz lambda:
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
Metoda UseStatusCodePagesWithRedirects rozšíření:
- Odešle klientovi stavový kód 302 .
- Přesměruje klienta do umístění zadaného v šabloně adresy URL.
app.UseStatusCodePagesWithRedirects("/StatusCode?code={0}");
Šablona adresy URL může obsahovat {0}
zástupný symbol pro stavový kód, jak je znázorněno v příkladu. Pokud šablona adresy URL začíná vlnovkou ~
, ~
nahradí se aplikací PathBase
. Pokud v aplikaci nasměrujete na koncový bod, vytvořte pro něj zobrazení nebo Razor stránku MVC. Razor Příklad stránky najdete Pages/StatusCode.cshtml
v ukázkové aplikaci.
Tato metoda se běžně používá v případě, že aplikace:
- Měl by přesměrovat klienta na jiný koncový bod, obvykle v případech, kdy jiná aplikace zpracovává chybu. U webových aplikací se adresní řádek prohlížeče klienta odráží přesměrovaný koncový bod.
- Nemělo by se zachovat a vrátit původní stavový kód s počáteční odpovědí přesměrování.
UseStatusCodePagesWithReExecute
Metoda UseStatusCodePagesWithReExecute rozšíření:
- Vrátí původní stavový kód klientovi.
- Vygeneruje tělo odpovědi opětovným spuštěním kanálu požadavku pomocí alternativní cesty.
app.UseStatusCodePagesWithReExecute("/StatusCode","?code={0}");
Pokud v aplikaci nasměrujete na koncový bod, vytvořte pro něj zobrazení nebo Razor stránku MVC. Ujistěte se UseStatusCodePagesWithReExecute
, že je před umístěním UseRouting
požadavku možné směrovat na stavovou stránku. Razor Příklad stránky najdete Pages/StatusCode.cshtml
v ukázkové aplikaci.
Tato metoda se běžně používá, když by aplikace měla:
- Zpracujte požadavek bez přesměrování na jiný koncový bod. U webových aplikací se adresní řádek prohlížeče klienta odráží původně požadovaný koncový bod.
- Zachování a vrácení původního stavového kódu s odpovědí
Šablony adres URL a řetězce dotazu můžou obsahovat zástupný symbol ({0}
) pro stavový kód. Šablona adresy URL musí začínat lomítkem (/
). Při použití zástupného symbolu v cestě ověřte, že koncový bod (stránka nebo kontroler) může segment cesty zpracovat. Například Razor stránka pro chyby by měla přijmout volitelnou hodnotu segmentu cesty s direktivou @page
:
@page "{code?}"
Koncový bod, který chybu zpracuje, může získat původní adresu URL, která chybu vygenerovala, jak je znázorněno v následujícím příkladu:
var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
OriginalURL =
statusCodeReExecuteFeature.OriginalPathBase
+ statusCodeReExecuteFeature.OriginalPath
+ statusCodeReExecuteFeature.OriginalQueryString;
}
Neoznačí metodu akce obslužné rutiny chyby s atributy metody HTTP, například HttpGet
. Explicitní příkazy brání některým požadavkům v dosažení metody. Pokud by se neověřeným uživatelům mělo zobrazit zobrazení chyb, povolte anonymní přístup k metodě.
Zakázat stavové kódové stránky
Chcete-li zakázat stránky stavového kódu pro kontroler MVC nebo metodu [SkipStatusCodePages]
akce, použijte atribut.
Chcete-li zakázat stavové kódové stránky pro konkrétní požadavky v Razor metodě obslužné rutiny stránky nebo v kontroleru MVC, použijte IStatusCodePagesFeature:
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
Kód pro zpracování výjimek
Kód na stránkách zpracování výjimek může vyvolat výjimky. Často je vhodné, aby se produkční chybové stránky skládají z čistě statického obsahu.
Hlavičky odpovědi
Po odeslání hlaviček odpovědi:
- Aplikace nemůže změnit stavový kód odpovědi.
- Všechny stránky výjimek nebo obslužné rutiny se nedají spustit. Odpověď musí být dokončena nebo přerušeno připojení.
Zpracování výjimek serveru
Kromě logiky zpracování výjimek ve vaší aplikaci může implementace serveru HTTP zpracovávat některé výjimky. Pokud server zachytí výjimku před odesláním hlaviček odpovědí, server odešle odpověď 500 – Vnitřní chyba serveru bez textu odpovědi. Pokud server zachytí výjimku po odeslání hlaviček odpovědi, server připojení zavře. Požadavky, které vaše aplikace nezpracuje, zpracovává server. Všechny výjimky, ke kterým dochází, když server zpracovává požadavek, se zpracovává zpracováním výjimek serveru. Vlastní chybové stránky aplikace, middleware pro zpracování výjimek a filtry toto chování neovlivní.
Ošetření výjimek při spuštění
Pouze vrstva hostování může zpracovávat výjimky, které probíhají při spuštění aplikace. Hostitel lze nakonfigurovat tak, aby zaznamenával chyby při spuštění a zaznamenával podrobné chyby.
Vrstva hostování může zobrazit chybovou stránku zachycené chyby při spuštění pouze v případě, že k chybě dojde po vazbě adresy hostitele nebo portu. Pokud se vazba nezdaří:
- Vrstva hostování zaznamená kritickou výjimku.
- Proces dotnet se chybově ukončí.
- Pokud je Kestrelserver HTTP, nezobrazí se žádná chybová stránka.
Pokud je proces spuštěný ve službě IIS (nebo ve službě Aplikace Azure) nebo IIS Express, vrátí modul ASP.NET Core chybu procesu 502.5. Další informace najdete v tématu Řešení potíží ASP.NET Core ve službě Aplikace Azure a službě IIS.
Chybová stránka databáze
Middleware chybové stránky databáze zachycuje výjimky související s databází, které je možné vyřešit pomocí migrací entity Framework. Pokud dojde k těmto výjimkám, vygeneruje se odpověď HTML s podrobnostmi o možných akcích k vyřešení problému. Tato stránka by měla být povolená pouze ve vývojovém prostředí. Povolte stránku přidáním kódu do Startup.Configure
:
if (env.IsDevelopment())
{
app.UseDatabaseErrorPage();
}
UseDatabaseErrorPagevyžaduje balíček NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.
Filtry výjimek
V aplikacích MVC je možné nakonfigurovat filtry výjimek globálně nebo podle kontroleru nebo podle akce. V Razor aplikacích Pages je možné je nakonfigurovat globálně nebo podle modelu stránky. Tyto filtry zpracovávají všechny neošetřené výjimky, ke kterým dochází během provádění akce kontroleru nebo jiného filtru. Další informace najdete v tématu Filtry v ASP.NET Core.
Tip
Filtry výjimek jsou užitečné pro zachycení výjimek, ke kterým dochází v rámci akcí MVC, ale nejsou tak flexibilní jako middleware zpracování výjimek. Doporučujeme použít middleware. Filtry použijte pouze v případě, že potřebujete provádět zpracování chyb odlišně podle toho, jakou akci MVC zvolíte.
Chyby stavu modelu
Informace o tom, jak zpracovávat chyby stavu modelu, naleznete v tématu Vazby modelu a Ověření modelu.