Megosztás a következőn keresztül:


Hibák kezelése a ASP.NET Core-ban

Note

Ez nem a cikk legújabb verziója. Az aktuális kiadásról a cikk .NET 10-es verziójában olvashat.

Warning

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 .

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 Core API-k hibáinak kezelése.

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ő:

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.

Warning

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: ASP.NET Core futtatókörnyezetek.

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
  • Headers
  • 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:

A fejlesztői kivétellap animáltan jelenik meg az egyes kijelölt lapok 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.

Warning

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ásukat HttpContext 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 a OnPost 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, 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

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.";
        }
    }
}

Warning

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

Warning

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. Az interfész egyetlen metódust tartalmaz, TryHandleAsync, amely egy HttpContext és egy Exception paramétert kap.

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.

A köztes szoftver kivételkezelése a regisztrált kivételkezelőkön keresztül halad végig sorrendben, amíg az egyik vissza nem tér true a TryHandleAsync-ből, jelezve, hogy a kivétel el volt kezelve. Ha egy kivételkezelő kezel egy kivételt, visszatérhet true 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.

A .NET 10-től kezdve az alapértelmezett viselkedés az, hogy letiltja a diagnosztikák, például a naplók és metrikák kibocsátását, amikor a kezelt kivételek TryHandleAsync visszaadják a true értéket. Ez eltér a korábbi verzióktól (.NET 8 és 9), ahol a diagnosztika mindig ki lett bocsátva, függetlenül attól, hogy a kivételt kezelték-e. Az alapértelmezett viselkedés a SuppressDiagnosticsCallback beállítással módosítható.

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ér false, így megjelenik a fejlesztői kivétellap.

Más környezetekben:

  • 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ér, így megjelenik falseaz /Error oldal .

SuppressDiagnosticsCallback

A .NET 10-től elkezdve szabályozhatja, hogy az exception handling middleware diagnosztikákat ír-e a kezelt kivételekről azzal, hogy beállítja a SuppressDiagnosticsCallback tulajdonságot a ExceptionHandlerOptions elemen. Ez a visszahívás megkapja a kivétel kontextusát, és lehetővé teszi annak meghatározását, hogy a diagnosztika mellőzhető-e az adott kivétel vagy kérés alapján.

Ha vissza szeretne térni a .NET 8 és 9 viselkedésére, ahol a diagnosztika mindig kiváltásra kerül a kezelt kivételek esetében, állítsa úgy be a visszahívást, hogy az mindig visszaadja a következőt: false.

app.UseExceptionHandler(new ExceptionHandlerOptions
{
    SuppressDiagnosticsCallback = context => false
});

A diagnosztika feltételesen letiltható a kivétel típusa vagy más környezet alapján is:

app.UseExceptionHandler(new ExceptionHandlerOptions
{
    SuppressDiagnosticsCallback = context => context.Exception is ArgumentException
});

Ha egy kivételt semmilyen implementáció nem kezel IExceptionHandler (minden kezelő visszatér falseTryHandleAsync), a vezérlés visszaáll a köztes szoftver alapértelmezett viselkedésére és beállításaira, és a rendszer a köztes szoftver szokásos viselkedésének megfelelően bocsát ki diagnosztikát.

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 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.

Note

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.

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 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ásukat HttpContext 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.
  • 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 Accept é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ó.

  1. Használja a ProblemDetailsOptions.CustomizeProblemDetails-t
  2. Egyéni IProblemDetailsWriter használata
  3. 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 ProblemDetailsOptionsa következő kód szolgálCustomizeProblemDetails:

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 IProblemDetailsWriter előtt regisztrálni kell az egyénit AddRazorPages, 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.WriteAsynclehet 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 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 é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();

Warning

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

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 Core API-k hibáinak kezelése.

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ő:

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.

Warning

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: ASP.NET Core futtatókörnyezetek.

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
  • Headers
  • 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:

A fejlesztői kivétellap animáltan jelenik meg az egyes kijelölt lapok 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.

Warning

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ásukat HttpContext 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 a OnPost 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, 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

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.";
        }
    }
}

Warning

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

Warning

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ér false, így megjelenik a fejlesztői kivétellap.

Más környezetekben:

  • 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ér, így megjelenik falseaz /Error oldal .

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 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.

Note

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.

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 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ásukat HttpContext 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.
  • 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 Accept é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ó.

  1. Használja a ProblemDetailsOptions.CustomizeProblemDetails-t
  2. Egyéni IProblemDetailsWriter használata
  3. 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 ProblemDetailsOptionsa következő kód szolgálCustomizeProblemDetails:

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 IProblemDetailsWriter előtt regisztrálni kell az egyénit AddRazorPages, 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.WriteAsynclehet 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 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 é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();

Warning

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

Készítette: Tom Dykstra

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 Core API-k 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. ASP.NET Core-alkalmazások alapértelmezés szerint engedélyezik a fejlesztői kivételoldalt, ha mindkettő:

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: ASP.NET Core futtatókörnyezetek.

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
  • Headers

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.

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.

Warning

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ásukat HttpContext 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 a OnPost 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, 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

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.";
        }
    }
}

Warning

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

Warning

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 először meghívódik a kivétel kezelésére.
  • A kivétel naplózása után a TryHandleException metódus visszatér false, így megjelenik a fejlesztői kivétellap.

Más környezetekben:

  • A CustomExceptionHandler először meghívódik a kivétel kezelésére.
  • A kivétel naplózása után a TryHandleException metódus visszatér, így megjelenik falseaz /Error oldal .

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 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.

Note

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.

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 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ásukat HttpContext 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.
  • 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 Accept é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ó.

  1. Használja a ProblemDetailsOptions.CustomizeProblemDetails-t
  2. Egyéni IProblemDetailsWriter használata
  3. 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 ProblemDetailsOptionsa következő kód szolgálCustomizeProblemDetails:

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 IProblemDetailsWriter előtt regisztrálni kell az egyénit AddRazorPages, 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.WriteAsynclehet 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 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 é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();

Warning

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

Készítette: Tom Dykstra

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 Core API-k 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. ASP.NET Core-alkalmazások alapértelmezés szerint engedélyezik a fejlesztői kivételoldalt, ha mindkettő:

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: ASP.NET Core futtatókörnyezetek.

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
  • Headers

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.

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.

Warning

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ásukat HttpContext 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 a OnPost 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, 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

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.";
        }
    }
}

Warning

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

Warning

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 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.

Note

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.

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 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ásukat HttpContext 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.
  • 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 Accept é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ó.

  1. Használja a ProblemDetailsOptions.CustomizeProblemDetails-t
  2. Egyéni IProblemDetailsWriter használata
  3. 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 ProblemDetailsOptionsa következő kód szolgálCustomizeProblemDetails:

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 IProblemDetailsWriter előtt regisztrálni kell az egyénit AddRazorPages, 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.WriteAsynclehet 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 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 é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();

Warning

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

Készítette: Tom Dykstra

Ez a cikk az ASP.NET Core-webalkalmazásokban előforduló hibák kezelésének gyakori megközelítéseit ismerteti. Lásd: A webes API-khoz készült ASP.NET Core API-k 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. ASP.NET Core-alkalmazások alapértelmezés szerint engedélyezik a fejlesztői kivételoldalt, ha mindkettő:

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: ASP.NET Core futtatókörnyezetek.

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
  • Headers

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.

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.

Warning

Ha az alternatív csővezeték saját kivételt dob, a Kivételkezelő köztes réteg újradobja az eredeti kivételt.

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 a OnPost 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, 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

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.";
        }
    }
}

Warning

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

Warning

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 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.

Note

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.

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:

  • 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. 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.

További erőforrások

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: A webes API-khoz készült ASP.NET Core API-k hibáinak kezelése .

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: ASP.NET Core futtatókörnyezetek.

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
  • Sztringparaméterek lekérdezése, ha vannak ilyenek
  • Cookie-k, ha vannak ilyenek
  • Headers

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.

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.

Warning

Ha az alternatív csővezeték saját kivételt dob, a Kivételkezelő köztes réteg újradobja az eredeti kivételt.

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.

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ő metódusokat. Például a OnGet a GET-kivételek kezelésére, míg a OnPost 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, 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

Használja a IExceptionHandlerPathFeature elemet a kivétel és az eredeti kérési útvonal elérésére egy hibakezelőben. 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";
        }
    }
}

Warning

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

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:

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

Warning

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.

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. 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í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ó. 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 fájlból webBuilder.UseStartup<StartupUseStatusCodePages>();Program.cs.
  • Válassza ki a kezdőlap kezdőlapján található hivatkozásokat.

Note

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.

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ő 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 való teszteléshez távolítsa el a megjegyzéseket a(z) webBuilder.UseStartup<StartupFormat>();-ból/ből.

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:

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

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.

A UseStatusCodePages való teszteléshez távolítsa el a megjegyzéseket a(z) webBuilder.UseStartup<StartupStatusLambda>();-ból/ből.

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é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. 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 őrizze meg és ne adja vissza az eredeti állapotkódot az első átirányítási válasznál.

A UseStatusCodePages való teszteléshez távolítsa el a megjegyzéseket a(z) webBuilder.UseStartup<StartupSCredirect>();-ból/ből.

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 UseStatusCodePagesWithReExecuteUseRouting 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;
        }
    }
}

Egy Razor Pages példáért, lásd a Pages/MyStatusCode2.cshtml fájlt a mintapéldában.

A UseStatusCodePages való teszteléshez távolítsa el a megjegyzéseket a(z) webBuilder.UseStartup<StartupSCreX>();-ból/ből.

Á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. 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. 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 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.

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

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: A webes API-khoz készült ASP.NET Core API-k hibáinak kezelése .

Mintakód megtekintése vagy letöltése. (A letöltés menete.)

Fejlesztői kivétel oldal

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: ASP.NET Core futtatókörnyezetek.

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
  • Headers

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";
        }
    }
}

Warning

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

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.

Í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.

Warning

Ne osszon meg 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 ProdEnvironment az ErrorHandlerLambda előfeldolgozási irányelveket, és válassza a Kezdőlapon a Kivétel aktiválása lehetőséget.

UseStatusCodePages

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 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 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.

app.UseStatusCodePages(
    "text/plain", "Status code page, status code: {0}");

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:

app.UseStatusCodePages(async context =>
{
    context.HttpContext.Response.ContentType = "text/plain";

    await context.HttpContext.Response.WriteAsync(
        "Status code page, status code: " + 
        context.HttpContext.Response.StatusCode);
});

UseStatusCodePagesWithRedirects

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ébe 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.
  • 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:

  • 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 UseStatusCodePagesWithReExecuteUseRouting elé kerüljön, így a kérelmet át lehet irányítani az állapotlapra. Razor Példaként a Pages/StatusCode.cshtml oldalt lásd a mintaalkalmazásban.

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 Razor 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 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 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.

Tip

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