Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Figyelmeztetés
A ASP.NET Core ezen verziója már nem támogatott. További információ: .NET és .NET Core támogatási szabályzat. A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .
Fontos
Ezek az információk egy olyan előzetes termékre vonatkoznak, amelyet a kereskedelmi forgalomba kerülés előtt jelentősen módosíthatnak. A Microsoft nem vállal kifejezett vagy hallgatólagos szavatosságot az itt megadott információkra vonatkozóan.
A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .
Ez a cikk az ASP.NET Core-webalkalmazásokban előforduló hibák kezelésének gyakori megközelítéseit ismerteti. Lásd még: ASP.NET vezérlőalapú webes API-k hibáinak kezelése és a hibák kezelése minimális API-kban.
A Blazor jelen cikkben szereplő útmutatást kiegészítő vagy felülíró hibakezelési útmutatásért lásd: ASP.NET Core-alkalmazások Blazor hibáinak kezelése.
Fejlesztői kivételoldal
A Fejlesztői kivétel lap részletes információkat jelenít meg a nem kezelt kérelmek kivételeiről. A HTTP-folyamat szinkron és aszinkron kivételeinek rögzítésére és hibaválaszok létrehozására használja DeveloperExceptionPageMiddleware . A fejlesztői kivételoldal a köztes szoftver folyamatának korai szakaszában fut, hogy a következő köztes szoftverben megjelenő kezeletlen kivételeket észlelhesse.
ASP.NET Core-alkalmazások alapértelmezés szerint engedélyezik a fejlesztői kivételoldalt, ha mindkettő:
- Futtatás a fejlesztési környezetben.
- Az alkalmazás az aktuális sablonok, azaz a WebApplication.CreateBuilder használatával jött létre.
A korábbi sablonokkal, azaz a WebHost.CreateDefaultBuilder sablon használatával létrehozott alkalmazások a app.UseDeveloperExceptionPage
függvény hívásával engedélyezhetik a fejlesztői kivételoldalt.
Figyelmeztetés
Csak akkor engedélyezze a fejlesztői kivételoldalt, ha az alkalmazás a fejlesztői környezetben fut. Ne ossza meg nyilvánosan a részletes kivételadatokat, ha az alkalmazás éles környezetben fut. További információ a környezetek konfigurálásáról: Több környezet használata a ASP.NET Core-ban.
A Fejlesztői kivétel lap a következő információkat tartalmazhatja a kivételről és a kérésről:
- Verem nyomkövetése
- Lekérdezési sztringparaméterek, ha vannak ilyenek
- Cookie-k, ha vannak ilyenek
- Fejlécek
- Végpont metaadatai, ha vannak ilyenek
A fejlesztői kivételoldal nem garantáltan biztosít semmilyen információt. Használja a naplózást a teljes hibainformációkhoz.
Az alábbi képen egy minta fejlesztői kivétellap látható, amelyen animáció látható a lapok és a megjelenített információk megjelenítéséhez:
Egy fejlécet tartalmazó Accept: text/plain
kérésre válaszul a Fejlesztői kivételoldal a HTML helyett egyszerű szöveget ad vissza. Például:
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
Kivételkezelő lap
Ha egyéni hibakezelő lapot szeretne konfigurálni az éles környezethez, hívja meg a következőt UseExceptionHandler: . Ez a kivételkezelés köztes szoftver:
- Naplózza a kezeletlen kivételeket.
- A kérést újra végrehajtja egy másik folyamatban a megadott elérési út használatával. A rendszer nem hajtja végre újra a kérést, ha a válasz elindult. A sablon által létrehozott kód újra végrehajtja a kérést az
/Error
elérési út használatával.
Figyelmeztetés
Ha az alternatív csővezeték saját kivételt dob, a Kivételkezelő köztes réteg újradobja az eredeti kivételt.
Mivel ez a köztes szoftver újra tudja futtatni a kérési folyamatot:
- A köztes rétegeknek kezelniük kell a reentranciát ugyanazzal a kéréssel. Ez általában azt jelenti, hogy a hívás
_next
után megtisztítják az állapotukat, vagy a feldolgozásukatHttpContext
gyorsítótárazzák, hogy elkerüljék az újbóli elvégzést. A kérelem törzsének kezelésekor ez az eredmények pufferelését vagy gyorsítótárazását jelenti, ahogyan azt az Űrlapolvasó is teszi. - UseExceptionHandler(IApplicationBuilder, String) A sablonokban használt túlterhelés esetén csak a kérelem útvonala módosul, és az útvonaladatok törlődnek. A kérelemadatok, például a fejlécek, a metódusok és az elemek mind újra felhasználhatók as-is.
- A hatókörön belüli szolgáltatások változatlanok maradnak.
Az alábbi példában a UseExceptionHandler hozzáadja a kivételkezelő middleware-t a fejlesztési környezeteken kívüli környezetekben.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
A Razor Lapok alkalmazássablon egy Hibalapot (.cshtml
) és PageModel osztályt (ErrorModel
) biztosít a Lapok mappában. MVC-alkalmazások esetén a projektsablon tartalmaz egy Error
műveletmetódust és egy hibanézetet a Home vezérlőhöz.
A köztes szoftver kivételkezelése újra végrehajtja a kérést az eredeti HTTP-módszerrel. Ha egy hibakezelő végpont a HTTP-metódusok egy meghatározott halmazára korlátozódik, az csak az adott HTTP-metódusokhoz fut. Az attribútumot használó [HttpGet]
MVC-vezérlőművelet például csak GET-kérelmek esetén fut. Annak érdekében, hogy minden kérés elérje az egyéni hibakezelő lapot, ne korlátozza azokat a HTTP-metódusok meghatározott készletére.
A kivételek eltérő kezelése az eredeti HTTP-módszer alapján:
- A Razor Pages esetében hozzon létre több kezelő metódusokat. Például a
OnGet
a GET-kivételek kezelésére, míg aOnPost
a POST-kivételek kezelésére használható. - MVC esetén http-igeattribútumokat alkalmazhat több műveletre. Például a
[HttpGet]
a GET-kivételek kezelésére használható, és a[HttpPost]
a POST-kivételek kezelésére.
Ha engedélyezni szeretné, hogy a hitelesítés nélküli felhasználók megtekinthessék az egyéni hibakezelő lapot, győződjön meg arról, hogy támogatja a névtelen hozzáférést.
A kivétel elérése
Használja a IExceptionHandlerPathFeature elemet a kivétel és az eredeti kérési útvonal elérésére egy hibakezelőben. Az alábbi példa IExceptionHandlerPathFeature
a kidobott kivételről nyújt további információt:
[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.";
}
}
}
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
Kivételkezelő lambda
Az egyéni kivételkezelő lap alternatívájaként lambda adható meg a UseExceptionHandler-nek. A lambda használata lehetővé teszi a hiba elérését a válasz visszaadása előtt.
A következő kód egy lambdát használ a kivételkezeléshez:
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();
}
A lambda használatának másik módja, ha az állapotkódot a kivétel típusa alapján állítja be, ahogyan az alábbi példában is látható:
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
});
}
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
IExceptionHandler
Az IExceptionHandler egy olyan felület, amely visszahívást biztosít a fejlesztőnek az ismert kivételek központi helyen való kezelésére.
IExceptionHandler
implementációkat a IServiceCollection.AddExceptionHandler<T>
meghívásával regisztrálják. Az IExceptionHandler
példány élettartama singleton. Több implementáció is hozzáadható, és a rendszer a regisztrált sorrendben hívja meg őket.
Ha egy kivételkezelő kezel egy kérést, true
adhat vissza a feldolgozás leállításához. Ha egy kivételt egyetlen kivételkezelő sem kezel, akkor a vezérlés visszaesik a köztes szoftver alapértelmezett viselkedésére és beállításaira. Különböző metrikákat és naplókat bocsát ki a rendszer a kezelt és kezeletlen kivételek esetén.
Az alábbi példa egy implementációt IExceptionHandler
mutat be:
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);
}
}
}
Az alábbi példa bemutatja, hogyan regisztrálhat implementációt IExceptionHandler
függőséginjektáláshoz:
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
Ha az előző kód a fejlesztési környezetben fut:
- A
CustomExceptionHandler
először meghívódik a kivétel kezelésére. - A kivétel naplózása után a
TryHandleAsync
metódus visszatérfalse
, így megjelenik a fejlesztői kivétellap.
Más környezetekben:
-
CustomExceptionHandler
-t először hívják meg a kivétel kezelésére. - A kivétel naplózása után a
TryHandleAsync
metódus visszatér, így megjelenikfalse
az/Error
oldal .
Állapotkód-oldalak használata
Alapértelmezés szerint egy ASP.NET Core-alkalmazás nem biztosít állapotkódlapot a HTTP-hibaállapot-kódokhoz, például 404 – Nem található. Amikor az alkalmazás beállít egy HTTP 400-599 hibaállapot-kódot, amely nem tartalmaz törzset, az állapotkódot és egy üres választörzset ad vissza. Ha engedélyezni szeretné az alapértelmezett csak szöveges kezelőket a gyakori hibaállapot-kódokhoz, hívja meg UseStatusCodePages a Program.cs
-ben:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Hívás UseStatusCodePages
a köztes szoftverrel kapcsolatos kérések kezelése előtt. Hívja például a UseStatusCodePages
parancsot a statikus fájlok köztes rétege és az Endpoints Middleware előtt.
Ha UseStatusCodePages
nincs használatban, a végpont nélküli URL-címre való navigálás egy böngészőfüggő hibaüzenetet ad vissza, amely jelzi, hogy a végpont nem található. Amikor UseStatusCodePages
a rendszer meghívja, a böngésző a következő választ adja vissza:
Status Code: 404; Not Found
UseStatusCodePages
általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
Megjegyzés:
Az állapotkódlapok köztes szoftverei nem észlelnek kivételeket. Egyéni hibakezelő lap megadásához használja a kivételkezelő lapot.
UseStatusCodePages formátum sztring alkalmazásával
A válasz tartalomtípusának és szövegének testreszabásához használja azt a UseStatusCodePages túlterhelést, amely tartalomtípust és formázási sztringet vesz fel.
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}");
Az előző kódban a {0}
egy helyőrző a hibakód számára.
UseStatusCodePages
a formátumsztringet általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
UseStatusCodePages a lambda kifejezéssel
Az egyéni hibakezelési és válaszírási kód megadásához használja az UseStatusCodePages azon túlterhelését, amely elfogad egy lambda kifejezést:
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}");
});
A lambdát általában nem használják termelési környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
Állapotkód-oldalak használata átirányítással (UseStatusCodePagesWithRedirects)
A UseStatusCodePagesWithRedirects bővítmény metódusa:
- 302 – Talált állapotkódot küld az ügyfélnek.
- Átirányítja az ügyfelet az URL-sablonban megadott hibakezelési végpontra. A hibakezelő végpont általában hibainformációkat jelenít meg, és HTTP 200-et ad vissza.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Az URL-sablon tartalmazhat helyőrzőt {0}
az állapotkódhoz, ahogyan az az előző kódban is látható. Ha az URL-sablon ~ (tilde) jellel kezdődik ~
, akkor az ~
helyébe az alkalmazás PathBase
kerül. Amikor végpontot ad meg az alkalmazásban, hozzon létre egy MVC-nézetet vagy Razor lapot a végponthoz.
Ezt a módszert gyakran használják az alkalmazás esetében:
- Az ügyfelet egy másik végpontra kell átirányítani, általában olyan esetekben, amikor egy másik alkalmazás feldolgozza a hibát. Webalkalmazások esetén az ügyfél böngészőcímsávja az átirányított végpontot tükrözi.
- Ne őrizze meg és ne adja vissza az eredeti állapotkódot az első átirányítási válasznál.
UseStatusCodePagesWithReExecute
A UseStatusCodePagesWithReExecute bővítmény metódusa:
- A válasz törzsét úgy hozza létre, hogy egy másik elérési út használatával újra végrehajtja a kérelemfolyamatot.
- Nem módosítja az állapotkódot a folyamat ismételt végrehajtása előtt vagy után.
Az új folyamat végrehajtása megváltoztathatja a válasz állapotkódját, mivel az új folyamat teljes mértékben szabályozza az állapotkódot. Ha az új folyamat nem módosítja az állapotkódot, a rendszer elküldi az eredeti állapotkódot az ügyfélnek.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Ha az alkalmazásban egy végpont van megadva, hozzon létre egy MVC-nézetet vagy Razor lapot a végponthoz.
Ezt a módszert gyakran használják, amikor az alkalmazásnak a következőt kell használnia:
- A kérés feldolgozása egy másik végpontra való átirányítás nélkül. Webalkalmazások esetén az ügyfél böngészőcímsávja az eredetileg kért végpontot tükrözi.
- Őrizze meg és adja vissza az eredeti állapotkódot a válaszsal együtt.
Az URL-sablonnak kezdődnie kell, /
és tartalmaznia kell egy helyőrzőt {0}
az állapotkódhoz. Ha az állapotkódot lekérdezési sztring paraméterként szeretné átadni, adjon át egy második argumentumot a következőbe UseStatusCodePagesWithReExecute
: Például:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
A hibát feldolgozó végpont lekérheti a hibát létrehozó eredeti URL-címet, ahogyan az az alábbi példában látható:
[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}";
}
}
}
Mivel ez a köztes szoftver újra tudja futtatni a kérési folyamatot:
- A middleware-eknek kell kezelniük a reentranciát ugyanazzal a kéréssel. Ez általában azt jelenti, hogy vagy a hívás
_next
után tisztítják meg az állapotukat, vagy aHttpContext
-en gyorsítótárazzák a feldolgozást, hogy elkerüljék annak újbóli elvégzését. A kérelem törzsének kezelésekor ez azt jelenti, hogy az eredményeket vagy pufferelni, vagy gyorsítótárazni kell, mint az űrlapolvasó esetében. - A hatókörön belüli szolgáltatások változatlanok maradnak.
Állapotkódlapok letiltása
MVC-vezérlő vagy műveleti metódus állapotkódlapjainak letiltásához használja a [SkipStatusCodePages] attribútumot.
Ha le szeretné tiltani az állapotkódlapokat a Razor Pages-kezelő metódusban vagy egy MVC-vezérlőben megadott kérésekhez, használja a következőt IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kivételkezelési kód
A kivételkezelő lapok kódjai kivételeket is okozhatnak. A gyártási hibaoldalakat alaposan tesztelni kell, és fokozottan ügyelni kell arra, hogy elkerüljük a sajátjaik által okozott kivételeket.
Válaszfejlécek
A válasz fejléceinek elküldése után:
- Az alkalmazás nem tudja módosítani a válasz állapotkódját.
- A kivételoldalak vagy -kezelők nem futtathatók. A választ be kell fejezni, vagy megszakadt a kapcsolat.
Kiszolgálói kivételkezelés
Az alkalmazások kivételkezelési logikája mellett a HTTP-kiszolgáló implementációja is képes kezelni néhány kivételt. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése előtt, a kiszolgáló választörzs nélkül küld 500 - Internal Server Error
választ. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése után, a kiszolgáló bezárja a kapcsolatot. Az alkalmazás által nem kezelt kérelmeket a kiszolgáló kezeli. Minden kivételt, amely akkor fordul elő, amikor a kiszolgáló kezeli a kérést, a kiszolgáló kivételkezelése kezeli. Az alkalmazás egyéni hibaoldalai, a köztes szoftver kivételkezelése és a szűrők nem befolyásolják ezt a viselkedést.
Indítási kivétel kezelése
Csak az üzemeltetési réteg képes kezelni az alkalmazás indításakor előforduló kivételeket. A gazdagép konfigurálható az indítási hibák és a részletes hibák rögzítésére.
A fogadó réteg csak akkor jeleníthet meg hibalapot egy észlelt indítási hiba esetén, ha a hiba a gazdacím/port kötése után következik be. Ha a kötés sikertelen:
- Az üzemeltetési réteg kritikus kivételt naplóz.
- A dotnet-folyamat összeomlik.
- HTTP-kiszolgáló Kestrel állapotában nem jelenik meg hibaoldal.
Ha IIS-en (vagy Azure App Service-en) vagy IIS Expressen fut, az ASP.NET core modul502.5-ös folyamathibát ad vissza, ha a folyamat nem indítható el. További információ: ASP.NET Core hibaelhárítása az Azure App Service-ben és az IIS-ben.
Adatbázis hibaoldala
Az adatbázis fejlesztői lapjának kivételszűrője AddDatabaseDeveloperPageExceptionFilter rögzíti az adatbázissal kapcsolatos kivételeket, amelyek az Entity Framework Core migrálásával oldhatók meg. Ha ezek a kivételek előfordulnak, a rendszer HTML-választ hoz létre a probléma megoldásához szükséges lehetséges műveletek részleteivel. Ez a lap csak a fejlesztési környezetben engedélyezett. A következő kód hozzáadja az Adatbázis fejlesztői oldal kivételszűrőjét:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Kivételszűrők
Az MVC-alkalmazásokban a kivételszűrők globálisan, vezérlőnként vagy műveletenként konfigurálhatók. A Razor Pages-alkalmazásokban globálisan vagy oldalmodellenként konfigurálhatók. Ezek a szűrők kezelik a vezérlőművelet vagy egy másik szűrő végrehajtása során előforduló nem kezelt kivételeket. További információ: Szűrők a ASP.NET Core-ban.
A kivételszűrők hasznosak az MVC-műveletekben előforduló kivételek csapdába ejtéséhez, de nem olyan rugalmasak, mint a beépített kivételkezelő köztes szoftver, UseExceptionHandler. Javasoljuk, hogy használja UseExceptionHandler
, kivéve, ha a hibakezelést a választott MVC-művelet alapján eltérő módon kell elvégeznie.
Modellállapot-hibák
A modellállapot-hibák kezelésével kapcsolatos információkért tekintse meg a modellkötést és a modellérvényesítést ismertető témakört.
Probléma részletei
A probléma részletei nem az egyetlen válaszformátum a HTTP API-hibák leírásához, azonban gyakran használják őket a HTTP API-k hibáinak jelentésére.
A probléma részletei szolgáltatás implementálja a felületet, amely támogatja a IProblemDetailsService probléma részleteinek létrehozását a ASP.NET Core-ban. A AddProblemDetails(IServiceCollection) bővítménymetódus a IServiceCollection regisztrálja az alapértelmezett IProblemDetailsService
implementációt.
A ASP.NET Core-alkalmazásokban a következő köztes szoftver generálja a probléma részleteit HTTP-válaszok meghívásakorAddProblemDetails
, kivéve, ha a Accept
kérelem HTTP-fejléce nem tartalmazza a regisztrált IProblemDetailsWriter (alapértelmezett) által támogatott tartalomtípusokat: application/json
- ExceptionHandlerMiddleware: Probléma részleteit tartalmazó választ hoz létre, ha nincs definiálva egyéni kezelő.
- StatusCodePagesMiddleware: Alapértelmezés szerint létrehoz egy probléma részleteit tartalmazó választ.
-
DeveloperExceptionPageMiddleware: Probléma részleteit tartalmazó választ hoz létre a fejlesztési környezetben, amikor a kérelem HTTP-fejléce nem tartalmazza a
text/html
értéket.
Az alábbi kód úgy konfigurálja az alkalmazást, hogy probléma részleteit adja meg az összes olyan HTTP-ügyfél- és kiszolgálóhiba-válaszhoz, amely még nem rendelkezik törzstartalommal:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
A következő szakasz bemutatja, hogyan szabhatja testre a probléma részleteit tartalmazó választörzset.
A probléma részleteinek testreszabása
Az ProblemDetails
automatikus létrehozása az alábbi lehetőségek bármelyikével testre szabható.
- Használja a
ProblemDetailsOptions.CustomizeProblemDetails
-t - Egyéni
IProblemDetailsWriter
használata -
Hívja a
IProblemDetailsService
köztes szoftvert
CustomizeProblemDetails
művelet
A létrehozott probléma részletei testre szabhatók a használatával CustomizeProblemDetails, és a testreszabások az automatikusan létrehozott probléma részleteire lesznek alkalmazva.
A beállításhoz CustomizeProblemDetailsa következő kód szolgálProblemDetailsOptions:
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();
Például egy HTTP Status 400 Bad Request
végpont eredménye a következő probléma részletei választ ad vissza:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Egyéni IProblemDetailsWriter
A IProblemDetailsWriter implementáció létrehozható a speciális testreszabásokhoz.
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));
}
}
Jegyzet: Egyéni IProblemDetailsWriter
használata esetén a hívás AddRazorPages előtt regisztrálni kell az egyénit IProblemDetailsWriter
, AddControllers, AddControllersWithViews, vagy 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();
A Middleware-ből származó probléma részletei
Az ProblemDetailsOptions és CustomizeProblemDetails használatának egyik alternatív módszere, hogy a ProblemDetails-t köztes rétegben állítjuk be. A probléma részleteire adott választ a következő hívással IProblemDetailsService.WriteAsync
lehet megírni:
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();
Az előző kódban a minimális API-végpontok /divide
, és /squareroot
a várt egyéni hibaválaszt adja vissza a hibabemenethez.
Az API-vezérlő végpontjai az alapértelmezett hibaválaszt adják vissza a hibabemenetkor, nem pedig az egyéni problémamegoldást. A rendszer az alapértelmezett problémaválaszt adja vissza, mert az API-vezérlő a válaszstreambe írt a hibaállapotkódokkal kapcsolatos problémák részleteit, mielőtt IProblemDetailsService.WriteAsync
meghívták, és a válasz nem íródik újra.
Az alábbi ValuesController
visszaadja BadRequestResult, ami a válaszfolyamba ír, és így megakadályozza az egyéni probléma válaszának visszatérését.
[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));
}
}
A következő Values3Controller
a ControllerBase.Problem
eredményt adja vissza, így a várt egyéni probléma eredménye lesz:
[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));
}
}
Hozzon létre egy ProblemDetails adatcsomagot a kivételekhez
Fontolja meg a következő alkalmazást:
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();
Nem fejlesztési környezetekben, ha kivétel történik, a következő egy szabványos ProblemDetails-válasz , amelyet a rendszer visszaad az ügyfélnek:
{
"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"
}
A legtöbb alkalmazás esetében csak az előző kód szükséges a kivételekhez. Az alábbi szakasz azonban bemutatja, hogyan kaphat részletesebb választ a problémákra.
Az alternatíva az egyéni kivételkezelő lappal szemben az, hogy lambdát adjon meg a UseExceptionHandler. A lambda használata lehetővé teszi a hiba elérését és a probléma részleteit tartalmazó válasz megírását a következővel 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();
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
A probléma részleteinek létrehozására másik módszer a külső NuGet-csomag, a Hellang.Middleware.ProblemDetails használata, amely a kivételek és az ügyfélhibák leképezésére használható a probléma részleteire.
További erőforrások
- Mintakód megtekintése vagy letöltése (hogyan töltsd le)
- Az Azure App Service és az IIS ASP.NET Core hibaelhárítása
- Gyakori hibák elhárítása az Azure App Service-ben és az IIS-ben az ASP.NET Core esetén
- ASP.NET Core vezérlőalapú webes API-k hibáinak kezelése
- Minimális API-k hibáinak kezelése.
Ez a cikk az ASP.NET Core-webalkalmazásokban előforduló hibák kezelésének gyakori megközelítéseit ismerteti. Lásd még: ASP.NET vezérlőalapú webes API-k hibáinak kezelése és a hibák kezelése minimális API-kban.
Fejlesztői kivételoldal
A Fejlesztői kivétel lap részletes információkat jelenít meg a nem kezelt kérelmek kivételeiről. ASP.NET Core-alkalmazások alapértelmezés szerint engedélyezik a fejlesztői kivételoldalt, ha mindkettő:
- Futás a fejlesztési környezetben.
- Az aktuális sablonokkal létrehozott alkalmazás, azaz a WebApplication.CreateBuilder használatával.
WebHost.CreateDefaultBuilder
használatával készült alkalmazásoknak engedélyezniük kell a fejlesztői kivételoldalt aConfigure
-ben aapp.UseDeveloperExceptionPage
meghívásával.
A fejlesztői kivételoldal a köztes szoftver folyamatának korai szakaszában fut, hogy a következő köztes szoftverben megjelenő kezeletlen kivételeket észlelhesse.
A részletes kivételadatokat nem szabad nyilvánosan megjeleníteni, amikor az alkalmazás éles környezetben fut. További információ a környezetek konfigurálásáról: Több környezet használata a ASP.NET Core-ban.
A Fejlesztői kivétel lap a következő információkat tartalmazhatja a kivételről és a kérésről:
- Verem nyomkövetése
- Lekérdezési sztringparaméterek, ha vannak ilyenek
- Cookie-k, ha vannak ilyenek
- Fejlécek
A fejlesztői kivételoldal nem garantáltan biztosít semmilyen információt. Teljes hibainformációk megszerzéséhez használja a naplózást.
Kivételkezelő lap
Ha egyéni hibakezelő lapot szeretne konfigurálni az éles környezethez, használja a következőt UseExceptionHandler. Ez a kivételkezelés köztes szoftver:
- Elkapja és naplózza a kezeletlen kivételeket.
- A kérést újra végrehajtja egy másik folyamatban a megadott elérési út használatával. A rendszer nem hajtja végre újra a kérést, ha a válasz elindult. A sablon által létrehozott kód újra végrehajtja a kérést az
/Error
elérési út használatával.
Figyelmeztetés
Ha a másik folyamat saját magának új kivételt ad ki, a Kivételkezelő köztes szoftver újra dobja az eredeti kivételt.
Mivel ez a köztes szoftver újra tudja futtatni a kérési folyamatot:
- A köztes szoftvereknek képesnek kell lenniük a ki-be lépés kezelésére ugyanazzal a kéréssel. Ez általában azt jelenti, hogy vagy a hívás
_next
után megtisztítják az állapotukat, vagy a feldolgozásukat aHttpContext
gyorsítótárazásával elkerülik annak újbóli elvégzését. A kérés törzsének kezelésekor ez az eredmények pufferelését vagy gyorsítótárazását jelenti, hasonlóan ahhoz, ahogy az Űrlapolvasó működik. - UseExceptionHandler(IApplicationBuilder, String) A sablonokban használt túlterhelés esetén csak a kérelem útvonala módosul, és az útvonaladatok törlődnek. A kérelemadatok, például a fejlécek, a metódusok és az elemek mind újra felhasználhatók as-is.
- A hatókörön belüli szolgáltatások változatlanok maradnak.
Az alábbi példában UseExceptionHandler nem fejlesztői környezetben hozzáadja a kivételkezelő köztes szoftvert.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
A Razor Lapok alkalmazássablon egy Hibalapot (.cshtml
) és PageModel osztályt (ErrorModel
) biztosít a Lapok mappában. MVC-alkalmazások esetén a projektsablon tartalmaz egy Error
műveletmetódust és egy hibanézetet a Home vezérlőhöz.
A köztes szoftver kivételkezelése újra végrehajtja a kérést az eredeti HTTP-módszerrel. Ha egy hibakezelő végpont a HTTP-metódusok egy meghatározott halmazára korlátozódik, az csak az adott HTTP-metódusokhoz fut. Az attribútumot használó [HttpGet]
MVC-vezérlőművelet például csak GET-kérelmek esetén fut. Annak érdekében, hogy minden kérés elérje az egyéni hibakezelő lapot, ne korlátozza azokat a HTTP-metódusok meghatározott készletére.
A kivételek eltérő kezelése az eredeti HTTP-módszer alapján:
- A Razor Pages esetében hozzon létre több kezelő metódust. Például a
OnGet
a GET-kivételek kezelésére, míg aOnPost
a POST-kivételek kezelésére használható. - MVC esetén http-igeattribútumokat alkalmazhat több műveletre. Például használja a
[HttpGet]
-t a GET-kivételek kezelésére, és a[HttpPost]
-t a POST-kivételek kezelésére.
Ha engedélyezni szeretné, hogy a hitelesítés nélküli felhasználók megtekinthessék az egyéni hibakezelő lapot, győződjön meg arról, hogy támogatja a névtelen hozzáférést.
A kivétel elérése
A kivételt és az eredeti kérés elérési útját hibakezelőben a IExceptionHandlerPathFeature használatával érheti el. Az alábbi példa IExceptionHandlerPathFeature
a kidobott kivételről nyújt további információt:
[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.";
}
}
}
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
Kivételkezelő lambda
A egyéni kivételkezelő lap alternatívája, ha egy lambdát biztosít a UseExceptionHandler számára. A lambda használata lehetővé teszi a hiba elérését a válasz visszaadása előtt.
A következő kód egy lambdát használ a kivételkezeléshez:
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();
}
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
IExceptionHandler
IExceptionHandler egy olyan felület, amely visszahívást biztosít a fejlesztőnek egy központi helyen lévő ismert kivételek kezelésére.
IExceptionHandler
az implementációk regisztrálásához a IServiceCollection.AddExceptionHandler<T>
használják: [IServiceCollection.AddExceptionHandler<T>
]. Az IExceptionHandler
példány élettartama singleton. Több implementáció is hozzáadható, és a rendszer a regisztrált sorrendben hívja meg őket.
Ha egy kivételkezelő kezel egy kérést, true
adhat vissza a feldolgozás leállításához. Ha egy kivételt egyetlen kivételkezelő sem kezel, akkor a vezérlés visszaesik a köztes szoftver alapértelmezett viselkedésére és beállításaira. Különböző metrikákat és naplókat bocsát ki a rendszer a kezelt és kezeletlen kivételek esetén.
Az alábbi példa egy implementációt IExceptionHandler
mutat be:
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);
}
}
}
Az alábbi példa bemutatja, hogyan regisztrálhat implementációt IExceptionHandler
függőséginjektáláshoz:
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
Ha az előző kód a fejlesztési környezetben fut:
- A
CustomExceptionHandler
-t először a kivétel kezelésére hívják meg. - A kivétel naplózása után a
TryHandleException
metódus visszatérfalse
, így megjelenik a fejlesztői kivétel oldal.
Más környezetekben:
- Először a
CustomExceptionHandler
hívódik meg a kivétel kezelésére. - A kivétel naplózása után a
TryHandleException
metódus visszatér, így megjelenikfalse
az/Error
oldal .
StatusCodePages használata
Alapértelmezés szerint egy ASP.NET Core-alkalmazás nem biztosít állapotkódlapot a HTTP-hibaállapot-kódokhoz, például 404 – Nem található. Amikor az alkalmazás beállít egy HTTP 400-599 hibaállapot-kódot, amely nem tartalmaz törzset, az állapotkódot és egy üres választörzset ad vissza. Ha engedélyezni szeretné az alapértelmezett csak szöveges kezelőket a gyakori hibaállapot-kódokhoz, hívja meg a következőt UseStatusCodePagesProgram.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Hívás UseStatusCodePages
a köztes szoftverrel kapcsolatos kérések kezelése előtt. Hívja meg például a UseStatusCodePages
a statikus fájl közbenső réteg és az végpontok közbenső réteg előtt.
Ha UseStatusCodePages
nincs használatban, a végpont nélküli URL-címre való navigálás egy böngészőfüggő hibaüzenetet ad vissza, amely jelzi, hogy a végpont nem található. Amikor UseStatusCodePages
a rendszer meghívja, a böngésző a következő választ adja vissza:
Status Code: 404; Not Found
UseStatusCodePages
általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
Megjegyzés:
Az állapotkódlapok köztes szoftverei nem észlelnek kivételeket. Egyéni hibakezelő lap megadásához használja a kivételkezelő lapot.
UseStatusCodePages formátum szöveggel
A válasz tartalomtípusának és szövegének testreszabásához használja a UseStatusCodePages metódusut, amely tartalomtípust és formázási sztringet veszi figyelembe.
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}");
Az előző kódban a {0}
a hibakód helyőrzőjeként szerepel.
UseStatusCodePages
a formátumsztringet általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
UseStatusCodePages lambda segítségével
Egyéni hibakezelési és válaszírási kód megadásához használja a lambda kifejezést fogadó UseStatusCodePages túlterhelést:
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
a lambdát általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
Használja az állapotkód-oldalakat átirányításokkal
A UseStatusCodePagesWithRedirects bővítmény metódusa:
- 302 – Talált állapotkódot küld az ügyfélnek.
- Átirányítja az ügyfelet az URL-sablonban megadott hibakezelési végpontra. A hibakezelő végpont általában hibainformációkat jelenít meg, és HTTP 200-et ad vissza.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Az URL-sablon tartalmazhat helyőrzőt {0}
az állapotkódhoz, ahogyan az az előző kódban is látható. Ha az URL-sablon ~
(tilde) karakterrel kezdődik, akkor az ~
helyére az alkalmazás PathBase
lép. Amikor végpontot ad meg az alkalmazásban, hozzon létre egy MVC-nézetet vagy Razor lapot a végponthoz.
Ezt a módszert gyakran használják az alkalmazás esetében:
- Az ügyfelet egy másik végpontra kell átirányítani, általában olyan esetekben, amikor egy másik alkalmazás feldolgozza a hibát. Webalkalmazások esetén az ügyfél böngészőcímsávja az átirányított végpontot tükrözi.
- Nem szabad megőrizni és visszaadni az eredeti állapotkódot a kezdeti átirányítási válaszban.
UseStatusCodePagesWithReExecute
A UseStatusCodePagesWithReExecute bővítmény metódusa:
- A válasz törzsét úgy hozza létre, hogy egy másik elérési út használatával újra végrehajtja a kérelemfolyamatot.
- Nem módosítja az állapotkódot a folyamat ismételt végrehajtása előtt vagy után.
Az új folyamat végrehajtása megváltoztathatja a válasz állapotkódját, mivel az új folyamat teljes mértékben szabályozza az állapotkódot. Ha az új folyamat nem módosítja az állapotkódot, a rendszer elküldi az eredeti állapotkódot az ügyfélnek.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Ha az alkalmazásban egy végpont van megadva, hozzon létre egy MVC-nézetet vagy Razor lapot a végponthoz.
Ezt a módszert gyakran használják, amikor az alkalmazásnak a következőt kell használnia:
- A kérés feldolgozása egy másik végpontra való átirányítás nélkül. Webalkalmazások esetén az ügyfél böngészőcímsávja az eredetileg kért végpontot tükrözi.
- Őrizze meg és adja vissza az eredeti állapotkódot a válaszsal együtt.
Az URL-sablonnak kezdődnie kell, /
és tartalmaznia kell egy helyőrzőt {0}
az állapotkódhoz. Ha az állapotkódot lekérdezési sztring paraméterként szeretné átadni, adjon át egy második argumentumot a következőbe UseStatusCodePagesWithReExecute
: Például:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
A hibát feldolgozó végpont lekérheti a hibát létrehozó eredeti URL-címet, ahogyan az az alábbi példában látható:
[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}";
}
}
}
Mivel ez a köztes szoftver újra tudja futtatni a kérési folyamatot:
- A middlewareeket kezelni kell újrabehatolással ugyanazon kérés esetén. Ez általában azt jelenti, hogy vagy megtisztítják az állapotukat a
_next
hívása után, vagy a feldolgozásukat aHttpContext
gyorsítótárazásán keresztül elvégezve elkerülik az újbóli feldolgozást. A kérelem törzsének kezelésekor ez az eredmények pufferelését vagy gyorsítótárazását jelenti, az űrlap olvasójához hasonlóan. - A hatókörön belüli szolgáltatások változatlanok maradnak.
Állapotkódlapok letiltása
MVC-vezérlő vagy műveleti metódus állapotkódlapjainak letiltásához használja a [SkipStatusCodePages] attribútumot.
Ha le szeretné tiltani az állapotkódlapokat a Razor Pages-kezelő metódusban vagy egy MVC-vezérlőben megadott kérésekhez, használja a következőt IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kivételkezelési kód
A kivételkezelő lapok kódjai kivételeket is okozhatnak. A gyártási hibaoldalakat alaposan tesztelni kell, és fokozottan ügyelni kell arra, hogy elkerüljék a saját maguk által okozott kivételeket.
Válaszfejlécek
A válasz fejléceinek elküldése után:
- Az alkalmazás nem tudja módosítani a válasz állapotkódját.
- A kivételoldalak vagy -kezelők nem futtathatók. A választ be kell fejezni, vagy megszakadt a kapcsolat.
Kiszolgálói kivételkezelés
Az alkalmazások kivételkezelési logikája mellett a HTTP-kiszolgáló implementációja is képes kezelni néhány kivételt. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése előtt, a kiszolgáló választörzs nélkül küld 500 - Internal Server Error
választ. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése után, a kiszolgáló bezárja a kapcsolatot. Az alkalmazás által nem kezelt kérelmeket a kiszolgáló kezeli. Minden kivételt, amely akkor fordul elő, amikor a kiszolgáló kezeli a kérést, a kiszolgáló kivételkezelése kezeli. Az alkalmazás egyéni hibaoldalai, a köztes szoftver kivételkezelése és a szűrők nem befolyásolják ezt a viselkedést.
Indítási kivétel kezelése
Csak az üzemeltetési réteg képes kezelni az alkalmazás indításakor előforduló kivételeket. A gazdagép konfigurálható az indítási hibák rögzítésére és a részletes hibák rögzítésére.
Az üzemeltetési réteg csak akkor jeleníthet meg hibalapot egy rögzített indítási hibához, ha a hiba a gazdagép címe/portkötése után következik be. Ha a kötés sikertelen:
- Az üzemeltetési réteg kritikus kivételt naplóz.
- A dotnet-folyamat összeomlik.
- Nem jelenik meg hibaoldal, amikor a HTTP-kiszolgáló Kestrel.
Ha IIS-en (vagy Azure App Service-en) vagy IIS Expressen fut, az ASP.NET core modul502.5-ös folyamathibát ad vissza, ha a folyamat nem indítható el. További információ: ASP.NET Core hibaelhárítása az Azure App Service-ben és az IIS-ben.
Adatbázis hibaoldala
Az adatbázis fejlesztői lapjának kivételszűrője AddDatabaseDeveloperPageExceptionFilter rögzíti az adatbázissal kapcsolatos kivételeket, amelyek az Entity Framework Core migrálásával oldhatók meg. Ha ezek a kivételek előfordulnak, a rendszer HTML-választ hoz létre a probléma megoldásához szükséges lehetséges műveletek részleteivel. Ez a lap csak a fejlesztési környezetben engedélyezett. A következő kód hozzáadja az Adatbázis fejlesztői oldal kivételszűrőjét:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Kivételszűrők
Az MVC-alkalmazásokban a kivételszűrők globálisan, vezérlőnként vagy műveletenként konfigurálhatók. A Razor Pages-alkalmazásokban globálisan vagy oldalmodellenként konfigurálhatók. Ezek a szűrők kezelik a vezérlőművelet vagy egy másik szűrő végrehajtása során előforduló nem kezelt kivételeket. További információ: Szűrők a ASP.NET Core-ban.
A kivételszűrők hasznosak az MVC-műveletekben előforduló kivételek elfogására, de nem olyan rugalmasak, mint a beépített kivételkezelő middleware, UseExceptionHandler. Javasoljuk, hogy használja UseExceptionHandler
, kivéve, ha a hibakezelést a választott MVC-művelet alapján eltérő módon kell elvégeznie.
Modellállapot-hibák
A modellállapot-hibák kezelésével kapcsolatos információkért tekintse meg a modellkötést és a modellérvényesítést ismertető témakört.
Probléma részletei
A probléma részletei nem az egyetlen válaszformátum a HTTP API-hibák leírásához, azonban gyakran használják őket a HTTP API-k hibáinak jelentésére.
A probléma részletei szolgáltatás implementálja a felületet, amely támogatja a IProblemDetailsService probléma részleteinek létrehozását a ASP.NET Core-ban. A AddProblemDetails(IServiceCollection) bővítménymetódus IServiceCollection regisztrálja az alapértelmezett IProblemDetailsService
implementációt.
Az ASP.NET Core-alkalmazásokban a következő köztes szoftver HTTP-válaszokat generál a probléma részleteivel, amikor meghívják AddProblemDetails
, kivéve, ha a Accept
kérelem HTTP-fejléce nem tartalmazza a regisztrált IProblemDetailsWriter által támogatott tartalomtípusok egyikét (alapértelmezett: application/json
).
- ExceptionHandlerMiddleware: Probléma részleteit tartalmazó választ hoz létre, ha nincs definiálva egyéni kezelő.
- StatusCodePagesMiddleware: Alapértelmezés szerint létrehoz egy probléma részleteit tartalmazó választ.
-
DeveloperExceptionPageMiddleware: Probléma részleteit tartalmazó választ generál a fejlesztési környezetben, ha a HTTP kérés fejléce nem tartalmazza a
text/html
Accept
.
Az alábbi kód úgy konfigurálja az alkalmazást, hogy probléma részleteit adja meg az összes olyan HTTP-ügyfél- és kiszolgálóhiba-válaszhoz, amely még nem rendelkezik törzstartalommal:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
A következő szakasz bemutatja, hogyan szabhatja testre a probléma részleteit tartalmazó választörzset.
A probléma részleteinek testreszabása
Az ProblemDetails
automatikus létrehozása az alábbi lehetőségek bármelyikével testre szabható.
- Használja a
ProblemDetailsOptions.CustomizeProblemDetails
-t - Egyéni
IProblemDetailsWriter
használata -
IProblemDetailsService
Köztes szoftver meghívása
CustomizeProblemDetails
művelet
A létrehozott probléma részletei testre szabhatók a használatával CustomizeProblemDetails, és a testreszabások az automatikusan létrehozott probléma részleteire lesznek alkalmazva.
A következő kód ProblemDetailsOptions használ CustomizeProblemDetails beállításához.
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();
Például egy végpont eredménye a következő probléma részleteit tartalmazó választörzset ad vissza:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Egyedi IProblemDetailsWriter
Egy IProblemDetailsWriter implementáció hozható létre speciális testreszabásokhoz.
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));
}
}
Megjegyzés: Ha egyéni IProblemDetailsWriter
-t használ, akkor az egyéni IProblemDetailsWriter
-t regisztrálnia kell a AddRazorPages, AddControllers, AddControllersWithViews vagy AddMvc hívása előtt.
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();
A Middleware-ből származó probléma részletei
Egy alternatív módja a ProblemDetailsOptions és a CustomizeProblemDetails használatának, hogy a ProblemDetails-t köztes szoftverben állítjuk be. A probléma részleteire adott választ a következő hívással IProblemDetailsService.WriteAsync
lehet megírni:
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();
Az előző kódban a minimális API-végpontok /divide
, és /squareroot
a várt egyéni hibaválaszt adja vissza a hibabemenethez.
Az API-vezérlő végpontjai az alapértelmezett hibaválaszt adják vissza a hibabemenetkor, nem pedig az egyéni problémamegoldást. A rendszer az alapértelmezett problémamegoldást adja vissza, mert az API-vezérlő a válaszstreambe írt, a hibaállapotkódokkal kapcsolatos problémák részleteit, mielőtt IProblemDetailsService.WriteAsync
meghívták, és a válasz nem lesz újra megírva.
Az alábbi ValuesController
visszaad egy értéket BadRequestResult, amely a válaszfolyamba ír, és így megakadályozza az egyéni probléma válaszának visszaadását.
[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));
}
}
A következő Values3Controller
visszaadja a ControllerBase.Problem
értéket, így a várt egyéni probléma eredményét kapjuk meg.
[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));
}
}
ProblemDetails adatcsomag létrehozása kivételekhez
Fontolja meg a következő alkalmazást:
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();
Nem fejlesztési környezetekben, ha kivétel történik, a következő egy szabványos ProblemDetails-válasz , amelyet a rendszer visszaad az ügyfélnek:
{
"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"
}
A legtöbb alkalmazás esetében csak az előző kód szükséges a kivételekhez. Az alábbi szakasz azonban bemutatja, hogyan kaphat részletesebb választ a problémákra.
Egy másik megoldás az egyéni kivételkezelő lap helyett, ha lambdát biztosítunk a UseExceptionHandler-hez. A lambda használata lehetővé teszi a hiba elérését és a probléma részleteit tartalmazó válasz megírását a következővel 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();
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
A probléma részleteinek létrehozására másik módszer a külső NuGet-csomag, a Hellang.Middleware.ProblemDetails használata, amely a kivételek és az ügyfélhibák leképezésére használható a probléma részleteire.
További erőforrások
- Mintakód megtekintése vagy letöltése (hogyan töltsd le)
- Az Azure App Service és az IIS ASP.NET Core hibaelhárítása
- Gyakori hibák elhárítása az Azure App Service-ben és az IIS-ben az ASP.NET Core esetén
- ASP.NET Core vezérlőalapú webes API-k hibáinak kezelése
- Minimális API-k hibáinak kezelése.
Ez a cikk az ASP.NET Core-webalkalmazásokban előforduló hibák kezelésének gyakori megközelítéseit ismerteti. Lásd még: ASP.NET vezérlőalapú webes API-k hibáinak kezelése és a hibák kezelése minimális API-kban.
Fejlesztői kivételoldal
A Fejlesztői kivétel lap részletes információkat jelenít meg a nem kezelt kérelmek kivételeiről. ASP.NET Core-alkalmazások alapértelmezés szerint engedélyezik a fejlesztői kivételoldalt, ha mindkettő:
- Futtatás a fejlesztési környezetben.
- Az aktuális sablonokkal létrehozott alkalmazás, azaz a WebApplication.CreateBuilder használatával.
WebHost.CreateDefaultBuilder
használatával készült alkalmazásoknak engedélyezniük kell a fejlesztői kivétellap megjelenítését, aConfigure
során aapp.UseDeveloperExceptionPage
hívásával.
A fejlesztői kivételoldal a köztes szoftver folyamatának korai szakaszában fut, hogy a következő köztes szoftverben megjelenő kezeletlen kivételeket észlelhesse.
A részletes kivételadatokat nem szabad nyilvánosan megjeleníteni, amikor az alkalmazás éles környezetben fut. További információ a környezetek konfigurálásáról: Több környezet használata a ASP.NET Core-ban.
A Fejlesztői kivétel lap a következő információkat tartalmazhatja a kivételről és a kérésről:
- Verem nyomkövetése
- Lekérdezési sztringparaméterek, ha vannak ilyenek
- Cookie-k, ha vannak ilyenek
- Fejlécek
A fejlesztői kivételoldal nem garantáltan biztosít semmilyen információt. A teljes hibainformációk naplózása .
Kivételkezelő lap
Ha egyéni hibakezelő lapot szeretne konfigurálni az éles környezethez, hívja meg a következőt UseExceptionHandler: . Ez a kivételkezelés köztes szoftver:
- Kezeli és naplózza a kezeletlen kivételeket.
- A kérést újra végrehajtja egy másik folyamatban a megadott elérési út használatával. A rendszer nem hajtja végre újra a kérést, ha a válasz elindult. A sablon által létrehozott kód újra végrehajtja a kérést az
/Error
elérési út használatával.
Figyelmeztetés
Ha az alternatív csővezeték kivételt dob, a kivételkezelő köztes szoftver újradobja az eredeti kivételt.
Mivel ez a köztes szoftver újra tudja futtatni a kérési folyamatot:
- A köztes szoftvereknek kezelniük kell az újbóli belépést ugyanazzal a kéréssel. Ez általában azt jelenti, hogy vagy megtisztítják az állapotukat a
_next
hívása után, vagy aHttpContext
gyorsítótárazzák a feldolgozásukat, hogy elkerüljék annak újbóli elvégzését. A kérelem törzsének kezelésekor ez az eredmények pufferelését vagy gyorsítótárazását jelenti, hasonlóan az űrlapolvasóhoz. - UseExceptionHandler(IApplicationBuilder, String) A sablonokban használt túlterhelés esetén csak a kérelem útvonala módosul, és az útvonaladatok törlődnek. A kérelemadatok, például a fejlécek, a metódusok és az elemek mind újra felhasználhatók as-is.
- A hatókörön belüli szolgáltatások változatlanok maradnak.
Az alábbi példában a UseExceptionHandler middleware hozzáadja a kivételkezelést nem fejlesztési környezetekben.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
A Razor Lapok alkalmazássablon egy Hibalapot (.cshtml
) és PageModel osztályt (ErrorModel
) biztosít a Lapok mappában. MVC-alkalmazások esetén a projektsablon tartalmaz egy Error
műveletmetódust és egy hibanézetet a Home vezérlőhöz.
A köztes szoftver kivételkezelése újra végrehajtja a kérést az eredeti HTTP-módszerrel. Ha egy hibakezelő végpont a HTTP-metódusok egy meghatározott halmazára korlátozódik, az csak az adott HTTP-metódusokhoz fut. Az attribútumot használó [HttpGet]
MVC-vezérlőművelet például csak GET-kérelmek esetén fut. Annak érdekében, hogy minden kérés elérje az egyéni hibakezelő lapot, ne korlátozza azokat a HTTP-metódusok meghatározott készletére.
A kivételek eltérő kezelése az eredeti HTTP-módszer alapján:
- A Razor Pageshez hozzon létre több kezelő metódust. Például, a
OnGet
a GET-kivételek kezelésére, aOnPost
pedig a POST-kivételek kezelésére használható. - MVC esetén http-igeattribútumokat alkalmazhat több műveletre. Például a
[HttpGet]
a GET-kivételek kezelésére és a[HttpPost]
a POST-kivételek kezelésére használható.
Ha engedélyezni szeretné, hogy a hitelesítés nélküli felhasználók megtekinthessék az egyéni hibakezelő lapot, győződjön meg arról, hogy támogatja a névtelen hozzáférést.
A kivétel elérése
Használja a IExceptionHandlerPathFeature-t a kivétel és az eredeti kérelem elérési útjának eléréséhez egy hibakezelőben. Az alábbi példa IExceptionHandlerPathFeature
a kidobott kivételről nyújt további információt:
[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.";
}
}
}
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
Kivételkezelő lambda
Egy alternatíva az egyéni kivételkezelő lap helyett, ha egy lambda-t biztosít UseExceptionHandler. A lambda használata lehetővé teszi a hiba elérését a válasz visszaadása előtt.
A következő kód egy lambdát használ a kivételkezeléshez:
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();
}
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
UseStatusCodePages
Alapértelmezés szerint egy ASP.NET Core-alkalmazás nem biztosít állapotkódlapot a HTTP-hibaállapot-kódokhoz, például 404 – Nem található. Amikor az alkalmazás beállít egy HTTP 400-599 hibaállapot-kódot, amely nem tartalmaz törzset, az állapotkódot és egy üres választörzset ad vissza. Ha engedélyezni szeretné az alapértelmezett csak szöveges kezelőket a gyakori hibaállapot-kódokhoz, hívja meg a következőt UseStatusCodePagesProgram.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Hívja a UseStatusCodePages
-t, mielőtt a köztes szoftver kéréseinek feldolgozását megkezdené. Például a UseStatusCodePages
-t hívja meg a Statikus fájl Middleware és az Endpoints Middleware előtt.
Ha UseStatusCodePages
nincs használatban, a végpont nélküli URL-címre való navigálás egy böngészőfüggő hibaüzenetet ad vissza, amely jelzi, hogy a végpont nem található. Amikor UseStatusCodePages
a rendszer meghívja, a böngésző a következő választ adja vissza:
Status Code: 404; Not Found
UseStatusCodePages
általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
Megjegyzés:
Az állapotkódlapok köztes szoftverei nem észlelnek kivételeket. Egyéni hibakezelő lap megadásához használja a kivételkezelő lapot.
UseStatusCodePages formátumsztring használatával
A válasz tartalomtípusának és szövegének testreszabásához használja a UseStatusCodePages túlterhelést, amely tartalomtípust és formátum sztringet vesz fel.
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}");
Az előző kódban a {0}
a hibakód helyőrzője.
UseStatusCodePages
a formátumsztringet általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
A StatusCode oldalakat lambda funkcióval használja
Az egyéni hibakezelési és válaszírási kód megadásához használja a UseStatusCodePages azon túlterhelését, amely lambda kifejezést fogad:
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
a lambda kifejezést általában nem használják termelési környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
UseStatusCodePagesWithRedirects
A UseStatusCodePagesWithRedirects bővítmény metódusa:
- 302 – Talált állapotkódot küld az ügyfélnek.
- Átirányítja az ügyfelet az URL-sablonban megadott hibakezelési végpontra. A hibakezelő végpont általában hibainformációkat jelenít meg, és HTTP 200-et ad vissza.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Az URL-sablon tartalmazhat helyőrzőt {0}
az állapotkódhoz, ahogyan az az előző kódban is látható. Ha az URL-sablon ~
(tilde) jellel kezdődik, az ~
részt az alkalmazás PathBase
-ra cseréli. Amikor végpontot ad meg az alkalmazásban, hozzon létre egy MVC-nézetet vagy Razor lapot a végponthoz.
Ezt a módszert gyakran használják az alkalmazás esetében:
- Az ügyfelet egy másik végpontra kell átirányítani, általában olyan esetekben, amikor egy másik alkalmazás feldolgozza a hibát. Webalkalmazások esetén az ügyfél böngészőcímsávja az átirányított végpontot tükrözi.
- Nem szabad megőriznie és visszaadnia az eredeti állapotkódot a kezdő átirányítási válaszban.
Használja az állapotkódos oldalakat újra végrehajtással
A UseStatusCodePagesWithReExecute bővítmény metódusa:
- A válasz törzsét úgy hozza létre, hogy egy másik elérési út használatával újra végrehajtja a kérelemfolyamatot.
- Nem módosítja az állapotkódot a folyamat ismételt végrehajtása előtt vagy után.
Az új folyamat végrehajtása megváltoztathatja a válasz állapotkódját, mivel az új folyamat teljes mértékben szabályozza az állapotkódot. Ha az új folyamat nem módosítja az állapotkódot, a rendszer elküldi az eredeti állapotkódot az ügyfélnek.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Ha az alkalmazásban egy végpont van megadva, hozzon létre egy MVC-nézetet vagy Razor lapot a végponthoz.
Ezt a módszert gyakran használják, amikor az alkalmazásnak a következőt kell használnia:
- A kérés feldolgozása egy másik végpontra való átirányítás nélkül. Webalkalmazások esetén az ügyfél böngészőcímsávja az eredetileg kért végpontot tükrözi.
- Őrizze meg és adja vissza az eredeti állapotkódot a válaszsal együtt.
Az URL-sablonnak kezdődnie kell, /
és tartalmaznia kell egy helyőrzőt {0}
az állapotkódhoz. Ha az állapotkódot lekérdezési sztring paraméterként szeretné átadni, adjon át egy második argumentumot a következőbe UseStatusCodePagesWithReExecute
: Például:
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
A hibát feldolgozó végpont lekérheti a hibát létrehozó eredeti URL-címet, ahogyan az az alábbi példában látható:
[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}";
}
}
}
Mivel ez a köztes szoftver újra tudja futtatni a kérési folyamatot:
- Az middleware-eknek kezelniük kell az újrabelépést ugyanazon kéréssel. Ez általában azt jelenti, hogy vagy a
_next
hívása után megtisztítják az állapotukat, vagy aHttpContext
-en végzett feldolgozásukat gyorsítótárazzák, hogy elkerüljék ennek újbóli elvégzését. A kérelemtörzs kezelésekor ez az eredmények pufferelését vagy gyorsítótárazását jelenti, mint például az Űrlapolvasónál. - A hatókörön belüli szolgáltatások változatlanok maradnak.
Állapotkódlapok letiltása
MVC-vezérlő vagy műveleti metódus állapotkódlapjainak letiltásához használja a [SkipStatusCodePages] attribútumot.
Ha le szeretné tiltani az állapotkódlapokat a Razor Pages-kezelő metódusban vagy egy MVC-vezérlőben megadott kérésekhez, használja a következőt IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kivételkezelési kód
A kivételkezelő lapok kódjai kivételeket is okozhatnak. A gyártási fázisban lévő hibaoldalakat alaposan tesztelni kell, és fokozottan ügyelni kell arra, hogy elkerüljük az általuk okozott kivételeket.
Válaszfejlécek
A válasz fejléceinek elküldése után:
- Az alkalmazás nem tudja módosítani a válasz állapotkódját.
- A kivételoldalak vagy -kezelők nem futtathatók. A választ be kell fejezni, vagy megszakadt a kapcsolat.
Kiszolgálói kivételkezelés
Az alkalmazások kivételkezelési logikája mellett a HTTP-kiszolgáló implementációja is képes kezelni néhány kivételt. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése előtt, a kiszolgáló választörzs nélkül küld 500 - Internal Server Error
választ. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése után, a kiszolgáló bezárja a kapcsolatot. Az alkalmazás által nem kezelt kérelmeket a kiszolgáló kezeli. Minden kivételt, amely akkor fordul elő, amikor a kiszolgáló kezeli a kérést, a kiszolgáló kivételkezelése kezeli. Az alkalmazás egyéni hibaoldalai, a köztes szoftver kivételkezelése és a szűrők nem befolyásolják ezt a viselkedést.
Indítási kivétel kezelése
Csak az üzemeltetési réteg képes kezelni az alkalmazás indításakor előforduló kivételeket. A gazdagép beállítható, hogy indítási hibákat rögzítsen és részletes hibákat rögzítsen.
A kiszolgálói réteg csak akkor jeleníthet meg hibaoldalt egy elfogott indítási hiba esetén, ha a hiba a gazdagép címének/portjának kötése után következik be. Ha a kötés sikertelen:
- Az üzemeltetési réteg kritikus kivételt naplóz.
- A dotnet-folyamat összeomlik.
- Nem jelenik meg hibalap, amikor az HTTP-kiszolgáló Kestrel.
Ha IIS-en (vagy Azure App Service-en) vagy IIS Expressen fut, az ASP.NET core modul502.5-ös folyamathibát ad vissza, ha a folyamat nem indítható el. További információ: ASP.NET Core hibaelhárítása az Azure App Service-ben és az IIS-ben.
Adatbázis hibaoldala
Az adatbázis fejlesztői lapjának kivételszűrője AddDatabaseDeveloperPageExceptionFilter rögzíti az adatbázissal kapcsolatos kivételeket, amelyek az Entity Framework Core migrálásával oldhatók meg. Ha ezek a kivételek előfordulnak, a rendszer HTML-választ hoz létre a probléma megoldásához szükséges lehetséges műveletek részleteivel. Ez a lap csak a fejlesztési környezetben engedélyezett. A következő kód hozzáadja az Adatbázis fejlesztői oldal kivételszűrőjét:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Kivételszűrők
Az MVC-alkalmazásokban a kivételszűrők globálisan, vezérlőnként vagy műveletenként konfigurálhatók. A Razor Pages-alkalmazásokban globálisan vagy oldalmodellenként konfigurálhatók. Ezek a szűrők kezelik a vezérlőművelet vagy egy másik szűrő végrehajtása során előforduló nem kezelt kivételeket. További információ: Szűrők a ASP.NET Core-ban.
A kivételszűrők hasznosak az MVC-műveletek során előforduló kivételek elkapásához, de nem olyan rugalmasak, mint a beépített kivételkezelő köztes szoftver. UseExceptionHandler Javasoljuk, hogy használja UseExceptionHandler
, kivéve, ha a hibakezelést a választott MVC-művelet alapján eltérő módon kell elvégeznie.
Modellállapot-hibák
A modellállapot-hibák kezelésével kapcsolatos információkért tekintse meg a modellkötést és a modellérvényesítést ismertető témakört.
Probléma részletei
A probléma részletei nem az egyetlen válaszformátum a HTTP API-hibák leírásához, azonban gyakran használják őket a HTTP API-k hibáinak jelentésére.
A probléma részletei szolgáltatás implementálja a felületet, amely támogatja a IProblemDetailsService probléma részleteinek létrehozását a ASP.NET Core-ban. A AddProblemDetails(IServiceCollection) bővítménymetódus IServiceCollection regisztrálja az alapértelmezett IProblemDetailsService
implementációt.
Az ASP.NET Core-alkalmazásokban a következő köztes szoftver generál HTTP-válaszokat, amelyek problémarészleteket tartalmaznak, amikor a AddProblemDetails
hívást kezdeményezik, kivéve, ha a Accept
kérelmi HTTP-fejlécek nem tartalmazzák a regisztrált IProblemDetailsWriter által támogatott tartalomtípusok egyikét (alapértelmezett: application/json
).
- ExceptionHandlerMiddleware: Probléma részleteit tartalmazó választ hoz létre, ha nincs definiálva egyéni kezelő.
- StatusCodePagesMiddleware: Alapértelmezés szerint létrehoz egy probléma részleteit tartalmazó választ.
-
DeveloperExceptionPageMiddleware: A kérés HTTP-fejléce nem tartalmazza a
text/html
elemet, ekkor fejlesztés során problémarészleteket tartalmazó választ generál aAccept
.
Az alábbi kód úgy konfigurálja az alkalmazást, hogy probléma részleteit adja meg az összes olyan HTTP-ügyfél- és kiszolgálóhiba-válaszhoz, amely még nem rendelkezik törzstartalommal:
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler();
app.UseHsts();
}
app.UseStatusCodePages();
A következő szakasz bemutatja, hogyan szabhatja testre a probléma részleteit tartalmazó választörzset.
A probléma részleteinek testreszabása
Az ProblemDetails
automatikus létrehozása az alábbi lehetőségek bármelyikével testre szabható.
- Használja a
ProblemDetailsOptions.CustomizeProblemDetails
-t - Egyéni
IProblemDetailsWriter
használata -
IProblemDetailsService
Hívja meg egy köztes szoftverben
CustomizeProblemDetails
művelet
A létrehozott probléma részletei testre szabhatók a használatával CustomizeProblemDetails, és a testreszabások az automatikusan létrehozott probléma részleteire lesznek alkalmazva.
A következő kód ProblemDetailsOptions használja a CustomizeProblemDetails beállításához:
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();
Például egy HTTP Status 400 Bad Request
végpont eredménye a következő probléma részleteit tartalmazó választörzset hoz létre.
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"nodeId": "my-machine-name"
}
Egyéni IProblemDetailsWriter
Speciális testreszabásokhoz implementáció hozható létre IProblemDetailsWriter.
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));
}
}
Jegyzet: Egyéni IProblemDetailsWriter
használata esetén az egyéni IProblemDetailsWriter
-et előbb regisztrálni kell, mielőtt a AddRazorPages, AddControllers, AddControllersWithViews vagy AddMvc hívás történik.
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();
A Middleware-ből származó probléma részletei
Alternatív megközelítés abban, hogy a ProblemDetailsOptions-t használjuk CustomizeProblemDetails-vel, az, hogy a ProblemDetails-t middleware-ben állítjuk be. A probléma részleteire adott választ a következő hívással IProblemDetailsService.WriteAsync
lehet megírni:
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();
Az előző kódban a minimális API-végpontok /divide
, és /squareroot
a várt egyéni hibaválaszt adja vissza a hibabemenethez.
Az API-vezérlő végpontjai az alapértelmezett hibaválaszt adják vissza a hibabemenetkor, nem pedig az egyéni problémamegoldást. A rendszer az alapértelmezett problémaválaszt adja vissza, mert az API-vezérlő a válaszstreambe írt a hibaállapotkódokkal kapcsolatos problémák részleteiről azelőtt, hogy a IProblemDetailsService.WriteAsync
meghívásra kerülne, és a válasz nem lesz újra megírva.
Az alábbi ValuesController
eredmény BadRequestResulta válaszfolyamba ír, és így megakadályozza az egyéni probléma válaszának visszaadását.
[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));
}
}
A következő Values3Controller
így adja vissza a ControllerBase.Problem
eredményt, tehát a várt egyéni probléma eredménye is visszaadódik.
[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));
}
}
Hozzon létre egy ProblemDetails-payloadot kivételekhez.
Fontolja meg a következő alkalmazást:
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();
Nem fejlesztési környezetekben, ha kivétel történik, a következő egy szabványos ProblemDetails-válasz , amelyet a rendszer visszaad az ügyfélnek:
{
"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"
}
A legtöbb alkalmazás esetében csak az előző kód szükséges a kivételekhez. Az alábbi szakasz azonban bemutatja, hogyan kaphat részletesebb választ a problémákra.
Az egyéni kivételkezelő oldal alternatívája, ha egy lambdát ad meg UseExceptionHandler-nek. A lambda használata lehetővé teszi a hiba elérését és a probléma részleteit tartalmazó válasz megírását a következővel 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();
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
A probléma részleteinek létrehozására másik módszer a külső NuGet-csomag, a Hellang.Middleware.ProblemDetails használata, amely a kivételek és az ügyfélhibák leképezésére használható a probléma részleteire.
További erőforrások
- Mintakód megtekintése vagy letöltése (hogyan töltsd le)
- Az Azure App Service és az IIS ASP.NET Core hibaelhárítása
- Gyakori hibák elhárítása az Azure App Service-ben és az IIS-ben az ASP.NET Core esetén
Ez a cikk az ASP.NET Core-webalkalmazásokban előforduló hibák kezelésének gyakori megközelítéseit ismerteti. Lásd: Hibák kezelése ASP.NET Core vezérlőalapú webes API-kban a webes API-khoz.
Fejlesztői kivételoldal
A Fejlesztői kivétel lap részletes információkat jelenít meg a nem kezelt kérelmek kivételeiről. ASP.NET Core-alkalmazások alapértelmezés szerint engedélyezik a fejlesztői kivételoldalt, ha mindkettő:
- Futtatás a fejlesztési környezetben.
- Az aktuális sablonokkal létrehozott alkalmazás, azaz a WebApplication.CreateBuilder használatával. Az
WebHost.CreateDefaultBuilder
használatával létrehozott alkalmazásoknak engedélyezniük kell a fejlesztői kivételoldalt aConfigure
történőapp.UseDeveloperExceptionPage
meghívásával.
A fejlesztői kivételoldal a köztes szoftver folyamatának korai szakaszában fut, hogy a következő köztes szoftverben megjelenő kezeletlen kivételeket észlelhesse.
A részletes kivételadatokat nem szabad nyilvánosan megjeleníteni, amikor az alkalmazás éles környezetben fut. További információ a környezetek konfigurálásáról: Több környezet használata a ASP.NET Core-ban.
A Fejlesztői kivétel lap a következő információkat tartalmazhatja a kivételről és a kérésről:
- Verem nyomkövetése
- Lekérdezési sztringparaméterek, ha vannak ilyenek
- Cookie-k, ha vannak ilyenek
- Fejlécek
A fejlesztői kivételoldal nem garantáltan biztosít semmilyen információt. Használja a naplózást a teljes hibainformációért.
Kivételkezelő lap
Ha egyéni hibakezelő lapot szeretne konfigurálni az éles környezethez, hívja meg a következőt UseExceptionHandler: . Ez a kivételkezelő köztes szoftver:
- Elfogja és naplózza a kezeletlen kivételeket.
- A kérést újra végrehajtja egy másik folyamatban a megadott elérési út használatával. A rendszer nem hajtja végre újra a kérést, ha a válasz elindult. A sablon által létrehozott kód újra végrehajtja a kérést az
/Error
elérési út használatával.
Figyelmeztetés
Ha az alternatív csatorna saját kivételt dob, a Kivételkezelő közvetítő szoftver újra dobja az eredeti kivételt.
Az alábbi példában a UseExceptionHandler a kivételkezelő köztes réteget nem fejlesztési környezetekben hozzáadja.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
A Razor Lapok alkalmazássablon egy Hibalapot (.cshtml
) és PageModel osztályt (ErrorModel
) biztosít a Lapok mappában. MVC-alkalmazások esetén a projektsablon tartalmaz egy Error
műveletmetódust és egy hibanézetet a Home vezérlőhöz.
A köztes szoftver kivételkezelése újra végrehajtja a kérést az eredeti HTTP-módszerrel. Ha egy hibakezelő végpont a HTTP-metódusok egy meghatározott halmazára korlátozódik, az csak az adott HTTP-metódusokhoz fut. Az attribútumot használó [HttpGet]
MVC-vezérlőművelet például csak GET-kérelmek esetén fut. Annak érdekében, hogy minden kérés elérje az egyéni hibakezelő lapot, ne korlátozza azokat a HTTP-metódusok meghatározott készletére.
A kivételek eltérő kezelése az eredeti HTTP-módszer alapján:
- A Razor Pages esetében hozzon létre több kezelő metódust. Például használja a
OnGet
kódot a GET-kivételek kezelésére, és aOnPost
kódot a POST-kivételek kezelésére. - MVC esetén http-igeattribútumokat alkalmazhat több műveletre. Például használja a
[HttpGet]
a GET-kivételek kezelésére, és használja a[HttpPost]
a POST-kivételek kezelésére.
Ha engedélyezni szeretné, hogy a hitelesítés nélküli felhasználók megtekinthessék az egyéni hibakezelő lapot, győződjön meg arról, hogy támogatja a névtelen hozzáférést.
A kivétel elérése
A hibakezelőben a kivétel és az eredeti kérelem elérési útjának eléréséhez használja a IExceptionHandlerPathFeature-t. Az alábbi példa IExceptionHandlerPathFeature
a kidobott kivételről nyújt további információt:
[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.";
}
}
}
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
Kivételkezelő lambda
Az egyéni kivételkezelő oldal alternatívája egy lambda biztosítása UseExceptionHandler. A lambda használata lehetővé teszi a hiba elérését a válasz visszaadása előtt.
A következő kód egy lambdát használ a kivételkezeléshez:
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();
}
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
Használja a státuszkódoldalakat
Alapértelmezés szerint egy ASP.NET Core-alkalmazás nem biztosít állapotkódlapot a HTTP-hibaállapot-kódokhoz, például 404 – Nem található. Amikor az alkalmazás beállít egy HTTP 400-599 hibaállapot-kódot, amely nem tartalmaz törzset, az állapotkódot és egy üres választörzset ad vissza. Ha engedélyezni szeretné az alapértelmezett csak szöveges kezelőket a gyakori hibaállapot-kódokhoz, hívja meg a következőt UseStatusCodePagesProgram.cs
:
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePages();
Hívja meg UseStatusCodePages
, mielőtt a köztes szoftver kezeli a kéréseket. Például, a UseStatusCodePages
hívása a Statikus fájl Middleware és az Endpoints Middleware előtt történjen.
Ha UseStatusCodePages
nincs használatban, a végpont nélküli URL-címre való navigálás egy böngészőfüggő hibaüzenetet ad vissza, amely jelzi, hogy a végpont nem található. Amikor UseStatusCodePages
a rendszer meghívja, a böngésző a következő választ adja vissza:
Status Code: 404; Not Found
UseStatusCodePages
általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
Megjegyzés:
Az állapotkódlapok köztes szoftverei nem észlelnek kivételeket. Egyéni hibakezelő lap megadásához használja a kivételkezelő lapot.
UseStatusCodePages formátum karakterlánccal
A válasz tartalomtípusának és szövegének testreszabásához használja a túlterhelést UseStatusCodePages, ami tartalomtípust és formázási sztringet fogad el:
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}");
A megelőző kódban a {0}
egy helyőrző a hibakód számára.
UseStatusCodePages
a formátumsztringet általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
A UseStatusCodePages függvény lambda kifejezéssel
Egyéni hibakezelési és válaszírási kód megadásához használja a UseStatusCodePages lambda kifejezés által lehetővé tett túlterhelést:
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
a lambdát általában nem használják éles környezetben, mert olyan üzenetet küld vissza, amely nem hasznos a felhasználók számára.
Állapotkód-oldalak használata átirányításokkal
A UseStatusCodePagesWithRedirects bővítmény metódusa:
- 302 – Talált állapotkódot küld az ügyfélnek.
- Átirányítja az ügyfelet az URL-sablonban megadott hibakezelési végpontra. A hibakezelő végpont általában hibainformációkat jelenít meg, és HTTP 200-et ad vissza.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");
Az URL-sablon tartalmazhat helyőrzőt {0}
az állapotkódhoz, ahogyan az az előző kódban is látható. Ha az URL-sablon ~
(tilde) karakterrel kezdődik, az ~
helyére az alkalmazás PathBase
kerül. Amikor végpontot ad meg az alkalmazásban, hozzon létre egy MVC-nézetet vagy Razor lapot a végponthoz.
Ezt a módszert gyakran használják az alkalmazás esetében:
- Az ügyfelet egy másik végpontra kell átirányítani, általában olyan esetekben, amikor egy másik alkalmazás feldolgozza a hibát. Webalkalmazások esetén az ügyfél böngészőcímsávja az átirányított végpontot tükrözi.
- Nem szabad megőrizni és visszaadni az eredeti állapotkódot az első átirányítási válaszban.
UseStatusCodePagesWithReExecute
A UseStatusCodePagesWithReExecute bővítmény metódusa:
- Az eredeti állapotkódot adja vissza az ügyfélnek.
- A válasz törzsét úgy hozza létre, hogy egy másik elérési út használatával újra végrehajtja a kérelemfolyamatot.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");
Ha az alkalmazásban egy végpont van megadva, hozzon létre egy MVC-nézetet vagy Razor lapot a végponthoz.
Ezt a módszert gyakran használják, amikor az alkalmazásnak a következőt kell használnia:
- A kérés feldolgozása egy másik végpontra való átirányítás nélkül. Webalkalmazások esetén az ügyfél böngészőcímsávja az eredetileg kért végpontot tükrözi.
- Őrizze meg és adja vissza az eredeti állapotkódot a válaszsal együtt.
Az URL-sablonnak kezdődnie kell, /
és tartalmaznia kell egy helyőrzőt {0}
az állapotkódhoz. Ha az állapotkódot lekérdezési sztring paraméterként szeretné átadni, adjon át egy második argumentumot a következőbe UseStatusCodePagesWithReExecute
: Például:
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
A hibát feldolgozó végpont lekérheti a hibát létrehozó eredeti URL-címet, ahogyan az az alábbi példában látható:
[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);
}
}
}
Állapotkódlapok letiltása
MVC-vezérlő vagy műveleti metódus állapotkódlapjainak letiltásához használja a [SkipStatusCodePages] attribútumot.
Ha le szeretné tiltani az állapotkódlapokat a Razor Pages-kezelő metódusban vagy egy MVC-vezérlőben megadott kérésekhez, használja a következőt IStatusCodePagesFeature:
public void OnGet()
{
var statusCodePagesFeature =
HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature is not null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kivételkezelési kód
A kivételkezelő lapok kódjai kivételeket is okozhatnak. Az éles hibaoldalakat alaposan tesztelni kell, és különösen ügyelni kell arra, hogy saját maguk ne dobjanak ki kivételeket.
Válaszfejlécek
A válasz fejléceinek elküldése után:
- Az alkalmazás nem tudja módosítani a válasz állapotkódját.
- A kivételoldalak vagy -kezelők nem futtathatók. A választ be kell fejezni, vagy megszakadt a kapcsolat.
Kiszolgálói kivételkezelés
Az alkalmazások kivételkezelési logikája mellett a HTTP-kiszolgáló implementációja is képes kezelni néhány kivételt. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése előtt, a kiszolgáló választörzs nélkül küld 500 - Internal Server Error
választ. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése után, a kiszolgáló bezárja a kapcsolatot. Az alkalmazás által nem kezelt kérelmeket a kiszolgáló kezeli. Minden kivételt, amely akkor fordul elő, amikor a kiszolgáló kezeli a kérést, a kiszolgáló kivételkezelése kezeli. Az alkalmazás egyéni hibaoldalai, a köztes szoftver kivételkezelése és a szűrők nem befolyásolják ezt a viselkedést.
Indítási kivétel kezelése
Csak az üzemeltetési réteg képes kezelni az alkalmazás indításakor előforduló kivételeket. Konfigurálható a kiszolgáló, hogy indítási hibákat rögzítsen és részletes hibákat rögzítsen.
Az hosztoló réteg csak akkor jeleníthet meg egy hibaüzenet oldalt egy rögzített indítási hibához, ha a hiba a host cím/port kötése után következik be. Ha a kötés sikertelen:
- Az üzemeltetési réteg kritikus kivételt naplóz.
- A dotnet-folyamat összeomlik.
- A HTTP-kiszolgáló Kestrel használatakor nem jelenik meg hibaüzenet oldal.
Ha IIS-en (vagy Azure App Service-en) vagy IIS Expressen fut, az ASP.NET core modul502.5-ös folyamathibát ad vissza, ha a folyamat nem indítható el. További információ: ASP.NET Core hibaelhárítása az Azure App Service-ben és az IIS-ben.
Adatbázis hibaoldala
Az adatbázis fejlesztői lapjának kivételszűrője AddDatabaseDeveloperPageExceptionFilter rögzíti az adatbázissal kapcsolatos kivételeket, amelyek az Entity Framework Core migrálásával oldhatók meg. Ha ezek a kivételek előfordulnak, a rendszer HTML-választ hoz létre a probléma megoldásához szükséges lehetséges műveletek részleteivel. Ez a lap csak a fejlesztési környezetben engedélyezett. A következő kód hozzáadja az Adatbázis fejlesztői oldal kivételszűrőjét:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();
Kivételszűrők
Az MVC-alkalmazásokban a kivételszűrők globálisan, vezérlőnként vagy műveletenként konfigurálhatók. A Razor Pages-alkalmazásokban globálisan vagy oldalmodellenként konfigurálhatók. Ezek a szűrők kezelik a vezérlőművelet vagy egy másik szűrő végrehajtása során előforduló nem kezelt kivételeket. További információ: Szűrők a ASP.NET Core-ban.
A kivételszűrők hasznosak az MVC-műveletekben előforduló kivételek elkapására, de nem olyan rugalmasak, mint a beépített kivételkezelő middleware. UseExceptionHandler Javasoljuk, hogy használja UseExceptionHandler
, kivéve, ha a hibakezelést a választott MVC-művelet alapján eltérő módon kell elvégeznie.
Modellállapot-hibák
A modellállapot-hibák kezelésével kapcsolatos információkért tekintse meg a modellkötést és a modellérvényesítést ismertető témakört.
További erőforrások
- Mintakód megtekintése vagy letöltése (hogyan töltsd le)
- Az Azure App Service és az IIS ASP.NET Core hibaelhárítása
- Gyakori hibák elhárítása az Azure App Service-ben és az IIS-ben az ASP.NET Core esetén
Kirk Larkin, Tom Dykstra és Steve Smith
Ez a cikk az ASP.NET Core-webalkalmazásokban előforduló hibák kezelésének gyakori megközelítéseit ismerteti. Lásd: Hibák kezelése ASP.NET Core vezérlőalapú webes API-kban a webes API-khoz.
Mintakód megtekintése vagy letöltése. (A letöltés menete.) Az F12 böngésző fejlesztői eszközeinek hálózati lapja hasznos a mintaalkalmazás tesztelése során.
Fejlesztői kivétel oldal
A Fejlesztői kivétel lap részletes információkat jelenít meg a nem kezelt kérelmek kivételeiről. A ASP.NET Core-sablonok a következő kódot generálják:
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();
});
}
Az előző kiemelt kód lehetővé teszi a fejlesztői kivételoldalt, ha az alkalmazás a fejlesztői környezetben fut.
A sablonok a köztes szoftver folyamatának korai szakaszában vannak elhelyezve UseDeveloperExceptionPage , hogy elkaphassák a következő köztes szoftverben kidobott kezeletlen kivételeket.
Az előző kód csak akkor engedélyezi a fejlesztői kivételoldalt, ha az alkalmazás a fejlesztői környezetben fut. A részletes kivételadatokat nem szabad nyilvánosan megjeleníteni, amikor az alkalmazás éles környezetben fut. További információ a környezetek konfigurálásáról: Több környezet használata a ASP.NET Core-ban.
A Fejlesztői kivétel lap a következő információkat tartalmazhatja a kivételről és a kérésről:
- Stack nyomvonal
- Sztringparaméterek lekérdezése, ha vannak ilyenek
- Cookie-k, ha vannak ilyenek
- Fejlécek
A fejlesztői kivételoldal nem garantáltan biztosít semmilyen információt. Használja a naplózást a teljes hibainformáció megszerzésére.
Kivételkezelő lap
Ha egyéni hibakezelő lapot szeretne konfigurálni az éles környezethez, hívja meg a következőt UseExceptionHandler: . Ez a kivételkezelés köztes szoftver:
- Elfogja és naplózza a kezeletlen kivételeket.
- A kérést újra végrehajtja egy másik folyamatban a megadott elérési út használatával. A rendszer nem hajtja végre újra a kérést, ha a válasz elindult. A sablon által létrehozott kód újra végrehajtja a kérést az
/Error
elérési út használatával.
Figyelmeztetés
Ha a másik csővezeték saját maga dob kivételt, a Kivételkezelő köztes réteg újra eldobja az eredeti kivételt.
Az alábbi példában a UseExceptionHandler a kivételkezelő köztes szoftvert adja hozzá a nem fejlesztési környezetekhez.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
A Razor Lapok alkalmazássablon egy Hibalapot (.cshtml
) és PageModel osztályt (ErrorModel
) biztosít a Lapok mappában. MVC-alkalmazások esetén a projektsablon tartalmaz egy Error
műveletmetódust és egy hibanézetet a Home vezérlőhöz.
A köztes szoftver kivételkezelése újra végrehajtja a kérést az eredeti HTTP-módszerrel. Ha egy hibakezelő végpont a HTTP-metódusok egy meghatározott halmazára korlátozódik, az csak az adott HTTP-metódusokhoz fut. Az attribútumot használó [HttpGet]
MVC-vezérlőművelet például csak GET-kérelmek esetén fut. Annak érdekében, hogy minden kérés elérje az egyéni hibakezelő lapot, ne korlátozza azokat a HTTP-metódusok meghatározott készletére.
A kivételek eltérő kezelése az eredeti HTTP-módszer alapján:
- A Razor Pages esetében hozzon létre több kezelési metódust. Például a
OnGet
használható a GET-kivételek kezelésére, és aOnPost
használható a POST-kivételek kezelésére. - MVC esetén http-igeattribútumokat alkalmazhat több műveletre. Például a
[HttpGet]
a GET-kivételek kezelésére, míg a[HttpPost]
a POST-kivételek kezelésére használható.
Ha engedélyezni szeretné, hogy a hitelesítés nélküli felhasználók megtekinthessék az egyéni hibakezelő lapot, győződjön meg arról, hogy támogatja a névtelen hozzáférést.
A kivétel elérése
Hibakezelőben használja a IExceptionHandlerPathFeature-t a kivételhez és az eredeti kérelem elérési útjához való hozzáféréshez. A következő kód hozzáadja ExceptionMessage
az ASP.NET Core-sablonok által létrehozott alapértelmezett Pages/Error.cshtml.cs
-hoz.
[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";
}
}
}
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
A kivétel tesztelése a mintaalkalmazásban:
- Állítsa be a környezetet élesre.
- Távolítsa el a megjegyzéseket a fájlból
webBuilder.UseStartup<Startup>();
Program.cs
. - Válassza a Kezdőlapon a Kivétel aktiválása lehetőséget.
Kivételkezelő lambda
Alternatívája az egyéni kivételkezelő lapnak, ha lambdát ad a UseExceptionHandler-nak. A lambda használata lehetővé teszi a hiba elérését a válasz visszaadása előtt.
A következő kód egy lambdát használ a kivételkezeléshez:
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();
});
}
Figyelmeztetés
Ne osszon meg bizalmas hibainformációkat IExceptionHandlerFeature vagy IExceptionHandlerPathFeature az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
A lambda kivételkezelésének tesztelése a mintaalkalmazásban:
- Állítsa be a környezetet élesre.
- Távolítsa el a megjegyzéseket a fájlból
webBuilder.UseStartup<StartupLambda>();
Program.cs
. - Válassza a Kezdőlapon a Kivétel aktiválása lehetőséget.
Állapotkód oldalak használata
Alapértelmezés szerint egy ASP.NET Core-alkalmazás nem biztosít állapotkódlapot a HTTP-hibaállapot-kódokhoz, például 404 – Nem található. Amikor az alkalmazás beállít egy HTTP 400-599 hibaállapot-kódot, amely nem tartalmaz törzset, az állapotkódot és egy üres választörzset ad vissza. Az állapotkódlapok megadásához használja az állapotkódlapok köztes szoftverét. Ha engedélyezni szeretné az alapértelmezett csak szöveges kezelőket a gyakori hibaállapot-kódokhoz, hívja meg UseStatusCodePages a Startup.Configure
metódust:
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();
});
}
Hívás UseStatusCodePages
a köztes szoftverrel kapcsolatos kérések kezelése előtt. Hívás például UseStatusCodePages
a Statikus fájl köztes szoftver és az Endpoints Middleware előtt.
Ha UseStatusCodePages
nincs használatban, a végpont nélküli URL-címre való navigálás egy böngészőfüggő hibaüzenetet ad vissza, amely jelzi, hogy a végpont nem található. Például a következőre navigálva: Home/Privacy2
. Amikor UseStatusCodePages
meghívják, a böngésző a következőt adja vissza:
Status Code: 404; Not Found
UseStatusCodePages
általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
Tesztelés UseStatusCodePages
a mintaalkalmazásban:
- Állítsa be a környezetet élesre.
- Távolítsa el a megjegyzéseket a
webBuilder.UseStartup<StartupUseStatusCodePages>();
objektumbólProgram.cs
objektumon belül. - Válassza ki a kezdőlap kezdőlapján található hivatkozásokat.
Megjegyzés:
Az állapotkódlapok köztes szoftverei nem észlelnek kivételeket. Egyéni hibakezelő lap megadásához használja a kivételkezelő lapot.
A UseStatusCodePages funkció formátumsztring használatával
A válasz tartalomtípusának és szövegének testreszabásához használja azt a UseStatusCodePages túlterhelést, amely tartalomtípust és formázási karakterláncot vesz.
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();
});
}
Az előzőleg említett kódban a {0}
a hibakód helyőrzője.
UseStatusCodePages
a formátumsztringet általában nem használják éles környezetben, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
A mintaalkalmazásban való teszteléshez távolítsa el a megjegyzéseket a(z) webBuilder.UseStartup<StartupFormat>();
Program.cs
-ból/ből.
Használja az állapotkódoldalakat lambdával
Az egyéni hibakezelési és válaszírási kód megadásához használja a UseStatusCodePages olyan változatát, amely lambda kifejezést vesz át:
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
lambdával általában nem használják gyakorlati alkalmazásban, mert olyan üzenetet ad vissza, amely nem hasznos a felhasználók számára.
A UseStatusCodePages
teszteléséhez a mintaalkalmazásban, távolítsa el a megjegyzéseket webBuilder.UseStartup<StartupStatusLambda>();
a Program.cs
részében.
UseStatusCodePagesWithRedirects
A UseStatusCodePagesWithRedirects bővítmény metódusa:
- 302 – Talált állapotkódot küld az ügyfélnek.
- Átirányítja az ügyfelet az URL-sablonban megadott hibakezelési végpontra. A hibakezelő végpont általában hibainformációkat jelenít meg, és HTTP 200-et ad vissza.
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();
});
}
Az URL-sablon tartalmazhat helyőrzőt {0}
az állapotkódhoz, ahogyan az az előző kódban is látható. Ha az URL-sablon ~
(tilde) jellel kezdődik, akkor az ~
helyére az alkalmazás PathBase
kerül. Amikor végpontot ad meg az alkalmazásban, hozzon létre egy MVC-nézetet vagy Razor lapot a végponthoz. A Razor Pages példáért lásd a Pages/MyStatusCode.cshtml fájlt a mintaalkalmazásban.
Ezt a módszert gyakran használják az alkalmazás esetében:
- Az ügyfelet egy másik végpontra kell átirányítani, általában olyan esetekben, amikor egy másik alkalmazás feldolgozza a hibát. Webalkalmazások esetén az ügyfél böngészőcímsávja az átirányított végpontot tükrözi.
- Ne tartsa meg és ne adja vissza az eredeti állapotkódot a kezdeti átirányítási válaszban.
A mintaalkalmazás teszteléséhez távolítsa el a megjegyzéseket a webBuilder.UseStartup<StartupSCredirect>();
-ből Program.cs
-ben.
UseStatusCodePagesWithReExecute
A UseStatusCodePagesWithReExecute bővítmény metódusa:
- Az eredeti állapotkódot adja vissza az ügyfélnek.
- A válasz törzsét úgy hozza létre, hogy egy másik elérési út használatával újra végrehajtja a kérelemfolyamatot.
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();
});
}
Ha az alkalmazásban egy végpont van megadva, hozzon létre egy MVC-nézetet vagy Razor lapot a végponthoz. Győződjön meg arról, hogy UseStatusCodePagesWithReExecute
UseRouting
elé kerüljön, így a kérelmet át lehet irányítani az állapotlapra. Egy Razor Pages példáért, lásd a Pages/MyStatusCode2.cshtml fájlt a mintapéldában.
Ezt a módszert gyakran használják, amikor az alkalmazásnak a következőt kell használnia:
- A kérés feldolgozása egy másik végpontra való átirányítás nélkül. Webalkalmazások esetén az ügyfél böngészőcímsávja az eredetileg kért végpontot tükrözi.
- Őrizze meg és adja vissza az eredeti állapotkódot a válaszsal együtt.
Az URL- és lekérdezési sztringsablonok tartalmazhatnak helyőrzőt {0}
az állapotkódhoz. Az URL-sablonnak a következővel /
kell kezdődnie: .
A hibát feldolgozó végpont lekérheti a hibát létrehozó eredeti URL-címet, ahogyan az az alábbi példában látható:
[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;
}
}
}
A Razor Pages mintát lásd a Pages/MyStatusCode2.cshtml fájlban a mintaalkalmazásban.
A mintaalkalmazásban való teszteléshez UseStatusCodePages
távolítsa el a megjegyzéseket a következőből webBuilder.UseStartup<StartupSCreX>();
Program.cs
: .
Állapotkódlapok letiltása
MVC-vezérlő vagy műveleti metódus állapotkódlapjainak letiltásához használja a [SkipStatusCodePages] attribútumot.
Ha le szeretné tiltani az állapotkódlapokat a Razor Pages-kezelő metódusban vagy egy MVC-vezérlőben megadott kérésekhez, használja a következőt IStatusCodePagesFeature:
public void OnGet()
{
// using Microsoft.AspNetCore.Diagnostics;
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
}
Kivételkezelési kód
A kivételkezelő lapok kódjai kivételeket is okozhatnak. Az éles hibaoldalakat alaposan tesztelni kell, és különösen ügyelni kell arra, hogy azok ne okozzanak saját kivételeket.
Válaszfejlécek
A válasz fejléceinek elküldése után:
- Az alkalmazás nem tudja módosítani a válasz állapotkódját.
- A kivételoldalak vagy -kezelők nem futtathatók. A választ be kell fejezni, vagy megszakadt a kapcsolat.
Kiszolgálói kivételkezelés
Az alkalmazások kivételkezelési logikája mellett a HTTP-kiszolgáló implementációja is képes kezelni néhány kivételt. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése előtt, a kiszolgáló választörzs nélkül küld 500 - Internal Server Error
választ. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése után, a kiszolgáló bezárja a kapcsolatot. Az alkalmazás által nem kezelt kérelmeket a kiszolgáló kezeli. Minden kivételt, amely akkor fordul elő, amikor a kiszolgáló kezeli a kérést, a kiszolgáló kivételkezelése kezeli. Az alkalmazás egyéni hibaoldalai, a köztes szoftver kivételkezelése és a szűrők nem befolyásolják ezt a viselkedést.
Indítási kivétel kezelése
Csak az üzemeltetési réteg képes kezelni az alkalmazás indításakor előforduló kivételeket. A gazdagép konfigurálható az indítási hibák és a részletes hibák rögzítésére.
Az üzemeltetési réteg csak akkor jeleníthet meg egy hibaoldalt egy rögzített indítási hiba esetén, ha a hiba a gazdagép címének/portjának kötése után következik be. Ha a kötés sikertelen:
- Az üzemeltetési réteg kritikus kivételt naplóz.
- A dotnet-folyamat összeomlik.
- A HTTP-kiszolgáló Kestrelhasználatakor nem jelenik meg hibalap.
Ha IIS-en (vagy Azure App Service-en) vagy IIS Expressen fut, az ASP.NET core modul502.5-ös folyamathibát ad vissza, ha a folyamat nem indítható el. További információ: ASP.NET Core hibaelhárítása az Azure App Service-ben és az IIS-ben.
Adatbázis hibaoldala
Az adatbázis fejlesztői lapjának kivételszűrője AddDatabaseDeveloperPageExceptionFilter
rögzíti az adatbázissal kapcsolatos kivételeket, amelyek az Entity Framework Core migrálásával oldhatók meg. Ha ezek a kivételek előfordulnak, a rendszer HTML-választ hoz létre a probléma megoldásához szükséges lehetséges műveletek részleteivel. Ez a lap csak a fejlesztési környezetben engedélyezett. Az egyes felhasználói fiókok megadásakor a ASP.NET Core Razor Pages-sablonok a következő kódot hozták létre:
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();
}
Kivételszűrők
Az MVC-alkalmazásokban a kivételszűrők globálisan, vezérlőnként vagy műveletenként konfigurálhatók. A Razor Pages-alkalmazásokban globálisan vagy oldalmodellenként konfigurálhatók. Ezek a szűrők kezelik a vezérlőművelet vagy egy másik szűrő végrehajtása során előforduló nem kezelt kivételeket. További információ: Szűrők a ASP.NET Core-ban.
A kivételszűrők hasznosak az MVC-műveletekben előforduló kivételek kezelésére, de nem olyan rugalmasak, mint a beépített kivételkezelő köztes szoftver. UseExceptionHandler
Javasoljuk, hogy használja UseExceptionHandler
, kivéve, ha a hibakezelést a választott MVC-művelet alapján eltérő módon kell elvégeznie.
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();
});
}
Modellállapot-hibák
A modellállapot-hibák kezelésével kapcsolatos információkért tekintse meg a modellkötést és a modellérvényesítést ismertető témakört.
További erőforrások
- Az Azure App Service és az IIS ASP.NET Core hibaelhárítása
- Gyakori hibák elhárítása az Azure App Service-ben és az IIS-ben az ASP.NET Core esetén
Ez a cikk az ASP.NET Core-webalkalmazásokban előforduló hibák kezelésének gyakori megközelítéseit ismerteti. Lásd: Hibák kezelése ASP.NET Core vezérlőalapú webes API-kban webes API-k esetén.
Mintakód megtekintése vagy letöltése. (A letöltés menete.)
Fejlesztői kivétel lap
A Fejlesztői kivétel lap részletes információkat jelenít meg a kérelemkivételekről. A ASP.NET Core-sablonok a következő kódot generálják:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
Az előző kód lehetővé teszi a fejlesztői kivételoldalt, ha az alkalmazás a fejlesztői környezetben fut.
A sablonok a UseDeveloperExceptionPage elemet minden köztes szoftver elé helyezik, így a következő köztes szoftverben fogják elkapni a kivételeket.
Az előző kód csak akkor engedélyezi a fejlesztői kivételoldalt , ha az alkalmazás a fejlesztői környezetben fut. A részletes kivételadatok nem jeleníthetők meg nyilvánosan, amikor az alkalmazás éles környezetben fut. További információ a környezetek konfigurálásáról: Több környezet használata a ASP.NET Core-ban.
A Fejlesztői kivétel lap a következő információkat tartalmazza a kivételről és a kérésről:
- Verem nyomkövetése
- Sztringparaméterek lekérdezése, ha vannak ilyenek
- Cookie-k, ha vannak ilyenek
- Fejlécek
Kivételkezelő lap
Ha egyéni hibakezelő oldalt szeretne konfigurálni az éles környezethez, használja az Exception Handling Middleware-t. A köztes szoftver:
- Fogások és naplók kivételei.
- Újra végrehajtja a kérést egy másik folyamatban a megjelölt lap vagy vezérlő számára. A rendszer nem hajtja végre újra a kérést, ha a válasz elindult. A sablon által létrehozott kód újravégrehajtja a kérést a következőre:
/Error
.
Az alábbi példában, UseExceptionHandler hozzáadja a Kivételkezelési köztes szoftvert a fejlesztési környezeten kívüli esetekben.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
A Razor Lapok alkalmazássablon egy Hibalapot (.cshtml
) és PageModel osztályt (ErrorModel
) biztosít a Lapok mappában. MVC-alkalmazások esetén a projektsablon tartalmaz egy hibaműveleti módszert és egy hibanézetet a Home vezérlőben.
Ne jelölje meg a hibakezelő műveleti metódust HTTP-metódusattribútumokkal, például HttpGet
. Az explicit igék megakadályozzák, hogy egyes kérések elérjék a metódust. Engedélyezze a névtelen hozzáférést a metódushoz, ha a hitelesítés nélküli felhasználóknak látniuk kell a hibanézetet.
A kivétel elérése
A hibakezelő vezérlőben vagy lapon használja a IExceptionHandlerPathFeature kódot a kivétel és az eredeti kérés útvonalának eléréséhez.
[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";
}
}
}
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
A kivételkezelési oldal aktiválásához állítsa a környezetet éles módra, és idézze elő a kivételt.
Kivételkezelő lambda
A kivételek kezelésére szolgáló egyéni oldal alternatívája az, ha lambda kifejezést biztosít az UseExceptionHandler számára. A lambda használata lehetővé teszi a hiba elérését a válasz visszaadása előtt.
Íme egy példa a lambda kivételkezelésre való használatára:
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();
}
Az előző kódban hozzáadásra kerül a await context.Response.WriteAsync(new string(' ', 512));
, hogy az Internet Explorer böngésző ne egy IE-hibaüzenetet, hanem maga a hibaüzenetet jelenítse meg. További információkért tekintse meg ezt a GitHub-problémát.
Figyelmeztetés
Ne szolgáljon ki bizalmas hibainformációkat IExceptionHandlerFeature vagy IExceptionHandlerPathFeature az ügyfeleknek. A hibák kiszolgálása biztonsági kockázatot jelent.
Ha meg szeretné tekinteni a lambda kivételkezelésének eredményét a mintaalkalmazásban, használja az és ErrorHandlerLambda
az ProdEnvironment
előfeldolgozási irányelveket, és válassza a Kezdőlapon a Kivétel aktiválása lehetőséget.
Állapotkód Oldalak Használata
Alapértelmezés szerint egy ASP.NET Core-alkalmazás nem biztosít állapotkódlapot a HTTP-állapotkódokhoz, például 404 – Nem található. Az alkalmazás egy állapotkódot és egy üres választörzset ad vissza. Állapotkódlapok megadásához használja az Állapotkódlapok köztes szoftvert.
A köztes szoftvert a Microsoft.AspNetCore.Diagnostics csomag teszi elérhetővé.
Ha engedélyezni szeretné az alapértelmezett csak szöveges kezelőket a gyakori hibaállapot-kódokhoz, hívja meg UseStatusCodePages a Startup.Configure
metódust:
app.UseStatusCodePages();
Hívja meg a UseStatusCodePages
igénykezelő köztes szoftvert (például a statikus fájl köztes szoftvert és az MVC köztes szoftvert) kezelése előtt.
Ha UseStatusCodePages
nincs használatban, a végpont nélküli URL-címre való navigálás egy böngészőfüggő hibaüzenetet ad vissza, amely jelzi, hogy a végpont nem található. Például navigálás a következőre Home/Privacy2
. Amikor UseStatusCodePages
meghívják, a böngésző a következőt adja vissza:
Status Code: 404; Not Found
UseStatusCodePages kódoldalakat formátum karakterlánccal
A válasz tartalomtípusának és szövegének testreszabásához használja a UseStatusCodePages metódust, amely tartalomtípust és formázási sztringet fogad.
app.UseStatusCodePages(
"text/plain", "Status code page, status code: {0}");
Használja a StatusCodePages-t lambda kifejezéssel
Egyéni hibakezelési és válaszírási kód megadásához használja a lambda kifejezést elfogadó túlterhelést UseStatusCodePages:
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
Használja az Állapotkód Oldalakat Átirányításokkal
A UseStatusCodePagesWithRedirects bővítmény metódusa:
- 302 – Talált állapotkódot küld az ügyfélnek.
- Átirányítja az ügyfelet az URL-sablonban megadott helyre.
app.UseStatusCodePagesWithRedirects("/StatusCode?code={0}");
Az URL-sablon tartalmazhat helyőrzőt {0}
az állapotkódhoz, ahogyan az a példában is látható. Ha az URL-sablon ~
(tilde) jellel kezdődik, akkor az ~
helyére az alkalmazás PathBase
kerül. Ha az alkalmazásban egy végpontra mutat, hozzon létre egy MVC nézetet vagy Razor lapot a végponthoz.
Razor Példaként a Pages/StatusCode.cshtml
oldalt lásd a mintaalkalmazásban.
Ezt a módszert gyakran használják az alkalmazás esetében:
- Az ügyfelet egy másik végpontra kell átirányítani, általában olyan esetekben, amikor egy másik alkalmazás feldolgozza a hibát. Webalkalmazások esetén az ügyfél böngészőcímsávja az átirányított végpontot tükrözi.
- Nem szabad megőrizni és visszaadni az eredeti állapotkódot a kezdeti átirányítási válasszal.
UseStatusCodePagesWithReExecute
A UseStatusCodePagesWithReExecute bővítmény metódusa:
- Az eredeti állapotkódot adja vissza az ügyfélnek.
- A válasz törzsét úgy hozza létre, hogy egy másik elérési út használatával újra végrehajtja a kérelemfolyamatot.
app.UseStatusCodePagesWithReExecute("/StatusCode","?code={0}");
Ha az alkalmazásban egy végpontra mutat, hozzon létre egy MVC nézetet vagy Razor lapot a végponthoz. Győződjön meg arról, hogy UseStatusCodePagesWithReExecute
a UseRouting
elé van helyezve, hogy a kérést át lehessen irányítani az állapotlapra.
Razor A Példák lapjaira a mintaalkalmazásban talál Pages/StatusCode.cshtml
példát.
Ezt a módszert gyakran használják, amikor az alkalmazásnak a következőt kell használnia:
- A kérés feldolgozása egy másik végpontra való átirányítás nélkül. Webalkalmazások esetén az ügyfél böngészőcímsávja az eredetileg kért végpontot tükrözi.
- Őrizze meg és adja vissza az eredeti állapotkódot a válaszsal együtt.
Az URL- és lekérdezési sztringsablonok tartalmazhatnak helyőrzőt ({0}
) az állapotkódhoz. Az URL-sablonnak perjellel (/
perjellel) kell kezdődnie. Ha helyőrzőt használ az elérési úton, győződjön meg arról, hogy a végpont (oldal vagy vezérlő) feldolgozhatja az elérési út szegmensét. Például egy hibaoldalnak támogatnia kell az opcionális útvonal szegmens értékét az @page
irányelvvel:
@page "{code?}"
A hibát feldolgozó végpont lekérheti a hibát létrehozó eredeti URL-címet, ahogyan az az alábbi példában látható:
var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
OriginalURL =
statusCodeReExecuteFeature.OriginalPathBase
+ statusCodeReExecuteFeature.OriginalPath
+ statusCodeReExecuteFeature.OriginalQueryString;
}
Ne jelölje meg a hibakezelő műveleti metódust HTTP-metódusattribútumokkal, például HttpGet
. Az explicit igék megakadályozzák, hogy egyes kérések elérjék a metódust. Engedélyezze a névtelen hozzáférést a metódushoz, ha a hitelesítés nélküli felhasználóknak látniuk kell a hibanézetet.
Állapotkódlapok letiltása
Ha le szeretné tiltani egy MVC-vezérlő vagy műveleti módszer állapotkódlapjait, használja az [SkipStatusCodePages]
attribútumot.
Ha le szeretné tiltani az állapotkódlapokat a Razor Pages-kezelő metódusban vagy egy MVC-vezérlőben megadott kérésekhez, használja a következőt IStatusCodePagesFeature:
var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();
if (statusCodePagesFeature != null)
{
statusCodePagesFeature.Enabled = false;
}
Kivételkezelési kód
A kivételkezelő lapok kódjai kivételeket okozhatnak. Gyakran jó ötlet, ha az éles hibaoldalak csak statikus tartalomból állnak.
Válaszfejlécek
A válasz fejléceinek elküldése után:
- Az alkalmazás nem tudja módosítani a válasz állapotkódját.
- A kivételoldalak vagy -kezelők nem futtathatók. A választ be kell fejezni, vagy megszakadt a kapcsolat.
Kiszolgálói kivételkezelés
Az alkalmazás kivételkezelési logikája mellett a HTTP-kiszolgáló implementációja is képes kezelni néhány kivételt. Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése előtt, a kiszolgáló választörzs nélkül küld egy 500 – belső kiszolgálói hibaválaszt . Ha a kiszolgáló kivételt kap a válaszfejlécek elküldése után, a kiszolgáló bezárja a kapcsolatot. Az alkalmazás által nem kezelt kérelmeket a kiszolgáló kezeli. Minden kivételt, amely akkor fordul elő, amikor a kiszolgáló kezeli a kérést, a kiszolgáló kivételkezelése kezeli. Az alkalmazás egyéni hibaoldalai, a köztes szoftver kivételkezelése és a szűrők nem befolyásolják ezt a viselkedést.
Indítási kivétel kezelése
Csak az üzemeltetési réteg képes kezelni az alkalmazás indításakor előforduló kivételeket. A gazdagép konfigurálható az indítási hibák és részletes hibák rögzítésére.
A tárhelyréteg hibalapot csak akkor tud megjeleníteni egy rögzített indítási hibához, ha a hiba a gazdagép címének/portjának kötése után következik be. Ha a kötés sikertelen:
- Az üzemeltetési réteg kritikus kivételt naplóz.
- A dotnet-folyamat összeomlik.
- HTTP-kiszolgáló Kestrelhasználatakor nem jelenik meg hibaoldal.
Ha IIS-en (vagy Azure App Service-en) vagy IIS Expressen fut, az ASP.NET core modul502.5-ös folyamathibát ad vissza, ha a folyamat nem indítható el. További információ: ASP.NET Core hibaelhárítása az Azure App Service-ben és az IIS-ben.
Adatbázis hibaoldala
Az Adatbázis Hibalap köztes szoftver rögzíti az adatbázissal kapcsolatos kivételeket, amelyeket az Entity Framework migráció alkalmazásával lehet megoldani. Amikor ilyen kivételek lépnek fel, a rendszer html-választ ad a probléma megoldásához szükséges lehetséges műveletek részleteivel. Ezt a lapot csak a fejlesztési környezetben szabad engedélyezni. Engedélyezze a lapot úgy, hogy kódot ad hozzá a következőhöz Startup.Configure
:
if (env.IsDevelopment())
{
app.UseDatabaseErrorPage();
}
UseDatabaseErrorPage A Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet csomag szükséges.
Kivételszűrők
Az MVC-alkalmazásokban a kivételszűrők globálisan, vezérlőnként vagy műveletenként konfigurálhatók. A Razor Pages-alkalmazásokban globálisan vagy oldalmodellenként konfigurálhatók. Ezek a szűrők kezelik azokat a kezeletlen kivételeket, amelyek egy vezérlőművelet vagy egy másik szűrő végrehajtása során fordulnak elő. További információ: Szűrők a ASP.NET Core-ban.
Jótanács
A kivétel-szűrők hasznosak az MVC-műveletekben előforduló kivételek kezelésére, de nem olyan rugalmasak, mint a kivételkezelő köztes szoftver. A köztes szoftver használatát javasoljuk. Csak akkor használjon szűrőket, ha a hibakezelést a választott MVC-művelet alapján eltérő módon kell elvégeznie.
Modellállapot-hibák
A modellállapot-hibák kezelésével kapcsolatos információkért tekintse meg a modellkötést és a modellérvényesítést ismertető témakört.
További erőforrások
- Az Azure App Service és az IIS ASP.NET Core hibaelhárítása
- Gyakori hibák elhárítása az Azure App Service-ben és az IIS-ben az ASP.NET Core esetén