Dela via


Hantera fel i ASP.NET Core

Notera

Det här är inte den senaste versionen av den här artikeln. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln.

Varning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i .NET och .NET Core Support Policy. För den aktuella utgåvan, se .NET 9-versionen av den här artikeln .

Viktig

Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.

Se den aktuella .NET 9-versionen av denna artikel.

Av Tom Dykstra

Den här artikeln beskriver vanliga metoder för att hantera fel i ASP.NET Core-webbappar. Se även Hantera fel i ASP.NET Core-styrenhetsbaserade webb-API:er och Hantera fel i minimala API:er.

Vägledning för Blazor felhantering som lägger till eller ersätter vägledningen i den här artikeln finns i Hantera fel i ASP.NET Core Blazor-appar.

Undantagssida för utvecklare

undantagssidan för utvecklare visar detaljerad information om ohanterade undantag för begäranden. Den använder DeveloperExceptionPageMiddleware för att samla in synkrona och asynkrona undantag från HTTP-pipelinen och för att generera felsvar. Undantagssidan för utvecklare körs tidigt i middleware-pipelinen, så att den kan fånga ohanterade undantag som genereras i efterföljande mellanprogram.

ASP.NET Core-appar aktiverar utvecklarens undantagssida som standard när båda:

Appar som skapats med hjälp av tidigare mallar, d.v.s. med hjälp av WebHost.CreateDefaultBuilder, kan aktivera undantagssidan för utvecklare genom att anropa app.UseDeveloperExceptionPage.

Varning

Aktivera inte undantagssidan för utvecklare om inte appen körs i utvecklingsmiljön. Dela inte detaljerad undantagsinformation offentligt när appen körs i produktion. Mer information om hur du konfigurerar miljöer finns i Använda flera miljöer i ASP.NET Core.

Sidan Undantag för utvecklare kan innehålla följande information om undantaget och begäran:

  • Stackspårning
  • Frågesträngsparametrar, om några
  • Cookies, om några
  • Rubriker
  • Slutpunktsmetadata, om några

Undantagssidan för utvecklare är inte garanterad att ange någon information. Använd logg för fullständig felinformation.

Följande bild visar ett exempel på en undantagssida för utvecklare med animering för att visa flikarna och informationen som visas:

Undantagssida för utvecklare animerad för att visa varje flik markerad.

Som svar på en begäran med en Accept: text/plain-rubrik returnerar undantagssidan för utvecklare oformaterad text i stället för HTML. Till exempel:

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

Undantagshanteringsida

Om du vill konfigurera en anpassad felhanteringssida för Produktionsmiljöanropar du UseExceptionHandler. Denna undantagshanterande mellanprogramvara:

  • Fångar upp och loggar ohanterade undantag.
  • Kör begäran igen i en alternativ pipeline med den sökväg som anges. Begäran utförs inte igen om svaret redan har påbörjats. Den mallgenererade koden kör begäran igen med hjälp av sökvägen /Error.

Varning

Om den alternativa pipelinen genererar ett eget undantag, överväxlar Undantagshantering mellanprogram det ursprungliga undantaget.

Eftersom det här mellanprogrammet kan köra pipelinen för begäran igen:

  • Mellanprogram måste hantera återinträde med samma begäran. Detta innebär normalt antingen att de rensar upp sitt tillstånd efter att ha anropat _next eller cachelagrar bearbetningen på HttpContext för att undvika att göra om den. När du hanterar begärandetexten innebär detta antingen buffring eller cachelagring av resultat som formulärläsaren.
  • För den UseExceptionHandler(IApplicationBuilder, String)-överbelastning som används i mallar ändras endast begärans sökväg och routdata rensas. Begär data som rubriker, metoder och objekt återanvänds alla as-is.
  • Begränsade tjänster förblir desamma.

I följande exempel lägger UseExceptionHandler till undantagshanteringsmellanprogram i miljöer som inte är utvecklingsmiljöer:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Appmallen Razor Pages innehåller en felsida (.cshtml) och PageModel -klass (ErrorModel) i mappen Pages. För en MVC-app innehåller projektmallen en Error-åtgärdsmetod och en felvy för den Home kontrollanten.

Undantagshanteringsmellanprogrammet kör begäran igen med hjälp av den ursprungliga HTTP-metoden. Om en slutpunkt för felhanterare är begränsad till en specifik uppsättning HTTP-metoder körs den endast för dessa HTTP-metoder. Till exempel körs en MVC-kontrollantåtgärd som använder attributet [HttpGet] endast för GET-begäranden. För att säkerställa att alla begäranden når sidan för anpassad felhantering ska du inte begränsa dem till en specifik uppsättning HTTP-metoder.

Så här hanterar du undantag på olika sätt baserat på den ursprungliga HTTP-metoden:

  • Skapa flera hanteringsmetoder för Razor Pages. Använd till exempel OnGet för att hantera GET-undantag och använda OnPost för att hantera POST-undantag.
  • För MVC använder du HTTP-verbattribut på flera åtgärder. Använd till exempel [HttpGet] för att hantera GET-undantag och använda [HttpPost] för att hantera POST-undantag.

Om du vill tillåta oautentiserade användare att visa sidan för anpassad felhantering kontrollerar du att den stöder anonym åtkomst.

Få åtkomst till undantaget

Använd IExceptionHandlerPathFeature för att komma åt undantaget och den ursprungliga sökvägen för begäran i en felhanterare. I följande exempel används IExceptionHandlerPathFeature för att få mer information om undantaget som utlöstes:

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

Varning

Tillhandahåll inte känslig felinformation till klienterna. Att hantera fel är en säkerhetsrisk.

Lambda för undantagshanterare

Ett alternativ till en anpassad undantagshanterarsida är att ange en lambda för UseExceptionHandler. Med hjälp av en lambda kan du komma åt felet innan svaret returneras.

Följande kod använder en lambda för undantagshantering:

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

Ett annat sätt att använda en lambda är att ange statuskoden baserat på undantagstypen, som i följande exempel:

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

Varning

Ge inte ut känslig felinformation till klienter. Serveringsfel är en säkerhetsrisk.

IExceptionHandler

IExceptionHandler är ett gränssnitt som ger utvecklaren ett återanrop för hantering av kända undantag på en central plats.

IExceptionHandler implementeringar registreras genom att anropa IServiceCollection.AddExceptionHandler<T>. Livslängden för en IExceptionHandler instans är singleton. Flera implementeringar kan läggas till och de anropas i den registrerade ordningen.

Om en undantagshanterare hanterar en begäran kan den returnera true för att stoppa bearbetningen. Om ett undantag inte hanteras av någon undantagshanterare återgår kontrollen till standardbeteendet och alternativen från mellanprogrammet. Olika mått och loggar genereras för hanterade och ohanterade undantag.

I följande exempel visas en IExceptionHandler implementering:

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

I följande exempel visas hur du registrerar en IExceptionHandler implementering för beroendeinmatning:

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

När föregående kod körs i utvecklingsmiljön:

  • CustomExceptionHandler anropas först för att hantera ett undantag.
  • Efter att ha loggat undantaget returnerar TryHandleAsync-metoden false, så visas undantagssidan för utvecklare.

I andra miljöer:

  • CustomExceptionHandler anropas först för att hantera ett undantag.
  • När du har loggat undantaget returnerar TryHandleAsync-metoden false, så /Error-sidan visas.

UseStatusCodePages

Som standard tillhandahåller en ASP.NET Core-app inte någon statuskodsida för HTTP-felstatuskoder, till exempel 404 – Hittades inte. När appen anger en HTTP 400-599-felstatuskod som inte har någon brödtext returneras statuskoden och en tom svarstext. Om du vill aktivera standardhanterare med endast text för vanliga felstatuskoder anropar du UseStatusCodePages i Program.cs:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePages();

Anropa UseStatusCodePages innan du begär hantering av mellanprogram. Anropa till exempel UseStatusCodePages före mellanskiktet för statiska filer och mellanskiktet för slutpunkter.

När UseStatusCodePages inte används returnerar navigering till en URL utan en slutpunkt ett webbläsarberoende felmeddelande som anger att slutpunkten inte kan hittas. När UseStatusCodePages anropas returnerar webbläsaren följande svar:

Status Code: 404; Not Found

UseStatusCodePages används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

Obs

Mellanprogrammet för statuskodsidor inte fånga undantag. Om du vill ange en anpassad felhanteringssida använder du sidan undantagshanterare.

Använd UseStatusCodePages med formatsträng

Om du vill anpassa svarsinnehållstypen och texten använder du överlagringen av UseStatusCodePages som tar en innehållstyp och formatsträng:

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

I föregående kod är {0} en platshållare för felkoden.

UseStatusCodePages med en formatsträng används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

UseStatusCodePages med lambda

Om du vill ange anpassad felhanterings- och svarsskrivningskod använder du överlagringen av UseStatusCodePages som tar ett lambda-uttryck:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePages(async statusCodeContext =>
{
    // using static System.Net.Mime.MediaTypeNames;
    statusCodeContext.HttpContext.Response.ContentType = Text.Plain;

    await statusCodeContext.HttpContext.Response.WriteAsync(
        $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

UseStatusCodePages med en lambda används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

UseStatusCodePagesWithRedirects

UseStatusCodePagesWithRedirects utökningsmetod:

  • Skickar en 302 – hittad statuskod till klienten.
  • Omdirigerar klienten till slutpunkten för felhantering som anges i URL-mallen. Slutpunkten för felhantering visar vanligtvis felinformation och returnerar HTTP 200.
var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

URL-mallen kan innehålla en {0} platshållare för statuskoden, enligt föregående kod. Om URL-mallen börjar med ~ (tilde) ersätts ~ av appens PathBase. När du anger en slutpunkt i appen skapar du en MVC-vy eller Razor sida för slutpunkten.

Den här metoden används ofta när appen:

  • Ska omdirigera klienten till en annan slutpunkt, vanligtvis i fall där en annan app bearbetar felet. För webbappar återspeglar klientens webbläsaradressfält den omdirigerade slutpunkten.
  • Bör inte bevara och returnera den ursprungliga statuskoden med det första omdirigeringssvaret.

UseStatusCodePagesWithReExecute

Extensionsmetoden UseStatusCodePagesWithReExecute:

  • Genererar svarstextens innehåll genom att köra begärandepipelinen igen med hjälp av en alternativ sökväg.
  • Ändrar inte statuskoden före eller efter att pipelinen körts om.

Den nya pipelinekörningen kan ändra svarets statuskod eftersom den nya pipelinen har fullständig kontroll över statuskoden. Om den nya pipelinen inte ändrar statuskoden skickas den ursprungliga statuskoden till klienten.

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");

Om en slutpunkt i appen har angetts skapar du en MVC-vy eller Razor sida för slutpunkten.

Den här metoden används ofta när appen ska:

  • Bearbeta begäran utan att omdirigera till en annan slutpunkt. För webbappar återspeglar klientens webbläsaradressfält den ursprungligen begärda slutpunkten.
  • Bevara och returnera den ursprungliga statuskoden med svaret.

URL-mallen måste börja med / och kan innehålla en platshållare {0} för statuskoden. Skicka statuskoden som en frågesträngsparameter genom att skicka ett andra argument till UseStatusCodePagesWithReExecute. Till exempel:

var app = builder.Build();  
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");

Slutpunkten som bearbetar felet kan hämta den ursprungliga URL:en som genererade felet, enligt följande exempel:

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

        }
    }
}

Eftersom det här mellanprogrammet kan köra pipelinen för begäran igen:

  • Mellanprogram måste hantera återaktivering med samma begäran. Detta innebär normalt antingen att de rensar upp sitt tillstånd efter att ha anropat _next eller cachelagrar bearbetningen på HttpContext för att undvika att göra om den. När du hanterar begärandetexten innebär detta antingen buffring eller cachelagring av resultat som formulärläsaren.
  • Begränsade tjänster förblir desamma.

Inaktivera statuskodsidor

Om du vill inaktivera statuskodsidor för en MVC-kontrollant eller åtgärdsmetod använder du attributet [SkipStatusCodePages].

Om du vill inaktivera statuskodsidor för specifika begäranden i en Razor Pages-hanteringsmetod eller i en MVC-styrenhet använder du IStatusCodePagesFeature:

public void OnGet()
{
    var statusCodePagesFeature =
        HttpContext.Features.Get<IStatusCodePagesFeature>();

    if (statusCodePagesFeature is not null)
    {
        statusCodePagesFeature.Enabled = false;
    }
}

Kod för undantagshantering

Kod i undantagshanteringssidor kan också utlösa undantag. Sidor med produktionsfel bör testas noggrant och vara extra noggranna för att undvika egna undantag.

Svarshuvuden

När rubrikerna för ett svar har skickats:

  • Appen kan inte ändra svarets statuskod.
  • Undantagssidor eller hanterare kan inte köras. Svaret måste slutföras eller så avbryts anslutningen.

Hantering av serverfel

Förutom logiken för undantagshantering i en app kan HTTP-serverimplementering hantera vissa undantag. Om servern upptäcker ett undantag innan svarshuvuden skickas skickar servern ett 500 - Internal Server Error svar utan svarstext. Om servern får ett undantag efter att svarsrubriker har skickats, stänger servern anslutningen. Begäranden som inte hanteras av appen hanteras av servern. Alla undantag som inträffar när servern hanterar begäran hanteras av serverns undantagshantering. Appens anpassade felsidor, undantagshantering av mellanprogram och filter påverkar inte det här beteendet.

Undantagshantering vid start

Endast värdlagret kan hantera undantag som sker under appstarten. Värden kan konfigureras för att fånga startfel och fånga detaljerade fel.

Värdlagret kan visa en felsida för ett insamlat startfel endast om felet inträffar efter värdadress/portbindning. Om bindningen misslyckas:

  • Värdlagret loggar ett kritiskt undantag.
  • Dotnet-processen kraschar.
  • Ingen felsida visas när HTTP-servern är Kestrel.

När du kör på IIS (eller Azure App Service) eller IIS Expressreturneras en 502.5 – Processfel av ASP.NET Core-modulen om processen inte kan starta. Mer information finns i Felsöka ASP.NET Core i Azure App Service och IIS.

Databasfelsida

Undantagsfiltret för databasutvecklare AddDatabaseDeveloperPageExceptionFilter samlar in databasrelaterade undantag som kan lösas med hjälp av Entity Framework Core-migreringar. När dessa undantag inträffar genereras ett HTML-svar med information om möjliga åtgärder för att lösa problemet. Den här sidan är endast aktiverad i utvecklingsmiljön. Följande kod lägger till undantagsfiltret för databasutvecklarens sida:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();

Undantagsfilter

I MVC-appar kan undantagsfilter konfigureras globalt eller per kontrollant eller per åtgärd. I Razor Pages-appar kan de konfigureras globalt eller per sidmodell. Dessa filter hanterar alla ohanterade undantag som inträffar under exekveringen av en controlleråtgärd eller ett annat filter. Mer information finns i filter i ASP.NET Core.

Undantagsfilter är användbara för att fånga undantag som inträffar inom MVC-åtgärder, men de är inte lika flexibla som den inbyggda undantagshantering av mellanprogram, UseExceptionHandler. Vi rekommenderar att du använder UseExceptionHandler, såvida du inte behöver utföra felhantering på olika sätt baserat på vilken MVC-åtgärd som väljs.

Modelltillståndsfel

Information om hur du hanterar modelltillståndsfel finns i Modellbindning och modellverifiering.

Probleminformation

Probleminformation är inte det enda svarsformatet som beskriver ett HTTP API-fel, men de används ofta för att rapportera fel för HTTP-API:er.

Tjänsten probleminformation implementerar IProblemDetailsService-gränssnittet, som har stöd för att skapa probleminformation i ASP.NET Core. AddProblemDetails(IServiceCollection)-tilläggsmetoden på IServiceCollection registrerar standardimplementeringen IProblemDetailsService.

I ASP.NET Core-appar genererar följande mellanprogramvara HTTP-svar med probleminformation när AddProblemDetails anropas, förutom när HTTP-huvudet för Accept-begäran inte innehåller någon av de innehållstyper som stöds av den registrerade IProblemDetailsWriter (standard: application/json):

Följande kod konfigurerar appen för att generera ett probleminformationssvar för alla HTTP-klient- och serverfelsvar som inte har brödtextinnehåll ännu:

builder.Services.AddProblemDetails();

var app = builder.Build();        

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler();
    app.UseHsts();
}

app.UseStatusCodePages();

I nästa avsnitt visas hur du anpassar svarstexten för probleminformation.

Anpassa probleminformation

Automatisk skapande av en ProblemDetails kan anpassas med något av följande alternativ:

  1. Använd ProblemDetailsOptions.CustomizeProblemDetails
  2. Använd en anpassad IProblemDetailsWriter
  3. Anropa IProblemDetailsService i ett mellanprogram

CustomizeProblemDetails åtgärd

Den genererade probleminformationen kan anpassas med hjälp av CustomizeProblemDetailsoch anpassningarna tillämpas på all probleminformation som genereras automatiskt.

Följande kod använder ProblemDetailsOptions för att ange CustomizeProblemDetails:

builder.Services.AddProblemDetails(options =>
    options.CustomizeProblemDetails = ctx =>
            ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));

var app = builder.Build();        

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler();
    app.UseHsts();
}

app.UseStatusCodePages();

Ett HTTP Status 400 Bad Request slutpunktsresultat skapar till exempel följande svarstext för probleminformation:

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "nodeId": "my-machine-name"
}

Anpassad IProblemDetailsWriter

En IProblemDetailsWriter implementering kan skapas för avancerade anpassningar.

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

Obs! När du använder en anpassad IProblemDetailsWritermåste den anpassade IProblemDetailsWriter registreras innan du anropar AddRazorPages, AddControllers, AddControllersWithViewseller 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();

Probleminformation från Middleware

Ett annat sätt att använda ProblemDetailsOptions med CustomizeProblemDetails är att ange ProblemDetails i mellanprogram. Ett probleminformationssvar kan skrivas genom att anropa IProblemDetailsService.WriteAsync:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseStatusCodePages();

// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
    await next(context);
    var mathErrorFeature = context.Features.Get<MathErrorFeature>();
    if (mathErrorFeature is not null)
    {
        if (context.RequestServices.GetService<IProblemDetailsService>() is
                                                           { } problemDetailsService)
        {
            (string Detail, string Type) details = mathErrorFeature.MathError switch
            {
                MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
                "https://en.wikipedia.org/wiki/Division_by_zero"),
                _ => ("Negative or complex numbers are not valid input.", 
                "https://en.wikipedia.org/wiki/Square_root")
            };

            await problemDetailsService.WriteAsync(new ProblemDetailsContext
            {
                HttpContext = context,
                ProblemDetails =
                {
                    Title = "Bad Input",
                    Detail = details.Detail,
                    Type = details.Type
                }
            });
        }
    }
});

// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
    if (denominator == 0)
    {
        var errorType = new MathErrorFeature { MathError =
                                               MathErrorType.DivisionByZeroError };
        context.Features.Set(errorType);
        return Results.BadRequest();
    }

    return Results.Ok(numerator / denominator);
});

// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
    if (radicand < 0)
    {
        var errorType = new MathErrorFeature { MathError =
                                               MathErrorType.NegativeRadicandError };
        context.Features.Set(errorType);
        return Results.BadRequest();
    }

    return Results.Ok(Math.Sqrt(radicand));
});

app.MapControllers();

app.Run();

I föregående kod returnerar de minimala API-slutpunkterna /divide och /squareroot det förväntade anpassade problemsvaret vid felindata.

API-kontrollantens slutpunkter returnerar standardfelsvaret vid felindata, inte det anpassade problemsvaret. Standardproblemsvaret returneras eftersom API-kontrollanten har skrivit till svarsströmmen Probleminformation för felstatuskoderinnan IProblemDetailsService.WriteAsync anropas och svaret inte skrivs igen.

Följande ValuesController returnerar BadRequestResult, vilket skriver till svarsströmmen och därför förhindrar att ett anpassat problemsvar returneras.

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

}

Följande Values3Controller returnerar ControllerBase.Problem så att det förväntade anpassade problemresultatet returneras:

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

}

Skapa en ProblemDetails-nyttolast för undantag

Tänk på följande app:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapControllers();
app.Run();

När ett undantag inträffar i icke-utvecklingsmiljöer är följande ett standardsvar ProblemDetails som returneras till klienten:

{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500,"traceId":"00-b644<snip>-00"
}

För de flesta appar är föregående kod allt som behövs för undantag. I följande avsnitt visas dock hur du får mer detaljerade problemsvar.

Ett alternativ till en anpassad undantagshanterarsida är att ange en lambda för UseExceptionHandler. Med hjälp av en lambda kan du komma åt felet och skriva ett probleminformationssvar med 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();

Varning

Lämna inte ut känslig felinformation till klienter. Att hantera fel är en säkerhetsrisk.

En annan metod för att generera probleminformation är att använda NuGet-paketet från tredje part Hellang.Middleware.ProblemDetails som kan användas för att mappa undantag och klientfel till probleminformation.

Ytterligare resurser

Av Tom Dykstra

Den här artikeln beskriver vanliga metoder för att hantera fel i ASP.NET Core-webbappar. Se även Hantera fel i ASP.NET Core-styrenhetsbaserade webb-API:er och Hantera fel i minimala API:er.

Undantagssida för utvecklare

undantagssidan för utvecklare visar detaljerad information om ohanterade undantag för begäranden. ASP.NET Core-appar aktiverar utvecklarens undantagssida som standard när båda:

Undantagssidan för utvecklare körs tidigt i mellanprogramspipelinen, så att den kan fånga ohanterade undantag som kastas i nästa mellanprogram.

Detaljerad undantagsinformation bör inte visas offentligt när appen körs i produktionsmiljön. Mer information om hur du konfigurerar miljöer finns i Använda flera miljöer i ASP.NET Core.

Sidan Undantag för utvecklare kan innehålla följande information om undantaget och begäran:

  • Stackspårning
  • Frågesträngsparametrar, om några
  • Cookies, om några
  • Rubriker

Undantagssidan för utvecklare är inte garanterad att ange någon information. Använd loggning för fullständig felinformation.

Undantagshanteringssida

Om du vill konfigurera en anpassad felhanteringssida för Produktionsmiljöanropar du UseExceptionHandler. Det här undantaget hanterar mellanprogram:

  • Fångar upp och loggar ohanterade undantag.
  • Kör begäran igen i en alternativ pipeline med den sökväg som anges. Begäran körs inte igen om svaret redan har börjat. Koden som skapats av mallen exekverar begäran på nytt med hjälp av sökvägen /Error.

Varning

Om den alternativa pipelinen genererar ett eget undantag, återkastar mellanprogrammet för undantagshantering det ursprungliga undantaget.

Eftersom det här mellanprogrammet kan köra pipelinen för begäran igen:

  • Mellanprogramvara måste hantera återentré med samma begäran. Detta innebär normalt antingen att de rensar upp sitt tillstånd efter att ha anropat _next eller cachelagrar bearbetningen på HttpContext för att undvika att göra om den. När du hanterar begärandetexten innebär detta antingen buffring eller cachelagring av resultat som formulärläsaren.
  • För UseExceptionHandler(IApplicationBuilder, String)-överbelastningen som används i mallar ändras endast förfrågans sökväg, och ruttdata rensas. Begär data som rubriker, metoder och objekt återanvänds alla as-is.
  • Begränsade tjänster förblir desamma.

I följande exempel lägger UseExceptionHandler till undantagshanteringsmellanprogram i miljöer som inte är utvecklingsmiljöer:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Appmallen Razor Pages innehåller en felsida (.cshtml) och PageModel -klass (ErrorModel) i mappen Pages. För en MVC-app innehåller projektmallen en Error-åtgärdsmetod och en felvy för den Home kontrollanten.

Undantaget hantering av mellanprogram kör begäran igen med hjälp av den ursprungliga HTTP-metoden. Om en slutpunkt för felhanterare är begränsad till en specifik uppsättning HTTP-metoder körs den endast för dessa HTTP-metoder. Till exempel körs en MVC-kontrollantåtgärd som använder attributet [HttpGet] endast för GET-begäranden. För att säkerställa att alla begäranden når sidan för anpassad felhantering ska du inte begränsa dem till en specifik uppsättning HTTP-metoder.

Så här hanterar du undantag på olika sätt baserat på den ursprungliga HTTP-metoden:

  • Skapa flera hanteringsmetoder för Razor Pages. Använd till exempel OnGet för att hantera GET-undantag och använda OnPost för att hantera POST-undantag.
  • För MVC använder du HTTP-verbattribut på flera åtgärder. Använd till exempel [HttpGet] för att hantera GET-undantag och använda [HttpPost] för att hantera POST-undantag.

Om du vill tillåta oautentiserade användare att visa sidan för anpassad felhantering kontrollerar du att den stöder anonym åtkomst.

Få åtkomst till undantaget

Använd IExceptionHandlerPathFeature för att komma åt undantaget och den ursprungliga sökvägen för begäran i en felhanterare. I följande exempel används IExceptionHandlerPathFeature för att få mer information om undantaget som utlöstes:

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

Varning

Gör inte tillhandahålla känslig felinformation till klienter. Att tillhandahålla fel är en säkerhetsrisk.

Lambda för undantagshanterare

Ett alternativ till en anpassad undantagshanterarsida är att ange en lambda för UseExceptionHandler. Med hjälp av en lambda kan du komma åt felet innan svaret returneras.

Följande kod använder en lambda för undantagshantering:

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

Varning

inte hantera känslig felinformation till klienter. Att servera fel är en säkerhetsrisk.

IExceptionHandler

IExceptionHandler är ett gränssnitt som ger utvecklaren ett återanrop för att hantera kända undantag på en central plats.

IExceptionHandler implementeringar registreras genom att anropa IServiceCollection.AddExceptionHandler<T> [IServiceCollection.AddExceptionHandler<T>]. Livslängden för en IExceptionHandler instans är singleton. Flera implementeringar kan läggas till och de anropas i den registrerade ordningen.

Om en undantagshanterare hanterar en begäran kan den returnera true för att stoppa bearbetningen. Om ett undantag inte hanteras av någon undantagshanterare återgår kontrollen till standardbeteendet och alternativen från mellanprogrammet. Olika mått och loggar genereras för hanterade och ohanterade undantag.

I följande exempel visas en IExceptionHandler implementering:

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

I följande exempel visas hur du registrerar en IExceptionHandler implementering för beroendeinmatning:

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

När föregående kod körs i utvecklingsmiljön:

  • CustomExceptionHandler anropas först för att hantera ett undantag.
  • Efter att undantaget har loggats returnerar TryHandleExceptionfalse, så visas undantagssidan för utvecklare.

I andra miljöer:

  • CustomExceptionHandler anropas först för att hantera ett undantag.
  • När du har loggat undantaget returnerar TryHandleException-metoden false, så /Error-sidan visas.

AnvändStatusKodSidor

Som standard tillhandahåller en ASP.NET Core-app inte någon statuskodsida för HTTP-felstatuskoder, till exempel 404 – Hittades inte. När appen anger en HTTP 400-599-felstatuskod som inte har någon brödtext returneras statuskoden och en tom svarstext. Om du vill aktivera standardhanterare med endast text för vanliga felstatuskoder anropar du UseStatusCodePages i Program.cs:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePages();

Anropa UseStatusCodePages innan du begär hantering av mellanprogram. Anropa till exempel UseStatusCodePages före mellanprogrammet för statiska filer och mellanprogrammet för slutpunkter.

När UseStatusCodePages inte används returnerar navigering till en URL utan en slutpunkt ett webbläsarberoende felmeddelande som anger att slutpunkten inte kan hittas. När UseStatusCodePages anropas returnerar webbläsaren följande svar:

Status Code: 404; Not Found

UseStatusCodePages används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

Not

Mellanprogrammet för statuskodsidor inte fånga undantag. För att ange en anpassad felhanteringssida använder du undantagshanterarsidan .

UseStatusCodePages med formatsträng

Om du vill anpassa svarsinnehållstypen och texten använder du överlagringen av UseStatusCodePages som tar en innehållstyp och formatsträng:

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

I föregående kod är {0} en platshållare för felkoden.

UseStatusCodePages med en formatsträng används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

UseStatusCodePages med lambda

Om du vill ange anpassad felhanterings- och svarsskrivningskod använder du överlagringen av UseStatusCodePages som tar ett lambda-uttryck:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePages(async statusCodeContext =>
{
    // using static System.Net.Mime.MediaTypeNames;
    statusCodeContext.HttpContext.Response.ContentType = Text.Plain;

    await statusCodeContext.HttpContext.Response.WriteAsync(
        $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

UseStatusCodePages med en lambda används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

AnvändStatusKodSidorMedOmdirigeringar

Metoden UseStatusCodePagesWithRedirects tillägg:

  • Skickar en 302 Found statuskod till klienten.
  • Omdirigerar klienten till slutpunkten för felhantering som anges i URL-mallen. Slutpunkten för felhantering visar vanligtvis felinformation och returnerar HTTP 200.
var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

URL-mallen kan innehålla en {0}-platshållare för statuskoden, som visas i föregående kodexempel. Om URL-mallen börjar med ~ (tilde) ersätts ~ av appens PathBase. När du anger en slutpunkt i appen skapar du en MVC-vy eller Razor sida för slutpunkten.

Den här metoden används ofta när appen:

  • Ska omdirigera klienten till en annan slutpunkt, vanligtvis i fall där en annan app bearbetar felet. För webbappar återspeglar klientens webbläsaradressfält den omdirigerade slutpunkten.
  • Bör inte bevara och returnera den ursprungliga statuskoden med det första omdirigeringssvaret.

AnvändStatusKodsSidorMedÅterExekvering

Metod för utökning UseStatusCodePagesWithReExecute:

  • Genererar svarstexten genom att köra begärandepipelinen igen med hjälp av en alternativ sökväg.
  • Ändrar inte statuskoden före eller efter att man har kört pipelinen igen.

Den nya pipelinekörningen kan ändra svarets statuskod eftersom den nya pipelinen har fullständig kontroll över statuskoden. Om den nya pipelinen inte ändrar statuskoden skickas den ursprungliga statuskoden till klienten.

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");

Om en slutpunkt i appen har angetts skapar du en MVC-vy eller Razor sida för slutpunkten.

Den här metoden används ofta när appen ska:

  • Bearbeta begäran utan att omdirigera till en annan slutpunkt. För webbappar återspeglar klientens webbläsaradressfält den ursprungligen begärda slutpunkten.
  • Bevara och returnera den ursprungliga statuskoden med svaret.

URL-mallen måste börja med / och kan innehålla en platshållare {0} för statuskoden. Skicka statuskoden som en frågesträngsparameter genom att skicka ett andra argument till UseStatusCodePagesWithReExecute. Till exempel:

var app = builder.Build();  
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");

Slutpunkten som bearbetar felet kan hämta den ursprungliga URL:en som genererade felet, enligt följande exempel:

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

        }
    }
}

Eftersom det här mellanprogrammet kan köra pipelinen för begäran igen:

  • Mellanprogram måste hantera återaktivering med samma begäran. Detta innebär normalt antingen att de rensar upp sitt tillstånd efter att ha anropat _next eller cachelagrar bearbetningen på HttpContext för att undvika att göra om den. När du hanterar begärandetexten innebär detta antingen buffring eller cachelagring av resultat som formulärläsaren.
  • Begränsade tjänster förblir desamma.

Inaktivera statuskodsidor

Om du vill inaktivera statuskodsidor för en MVC-kontrollant eller åtgärdsmetod använder du attributet [SkipStatusCodePages].

Om du vill inaktivera statuskodsidor för specifika begäranden i en Razor Pages-hanteringsmetod eller i en MVC-styrenhet använder du IStatusCodePagesFeature:

public void OnGet()
{
    var statusCodePagesFeature =
        HttpContext.Features.Get<IStatusCodePagesFeature>();

    if (statusCodePagesFeature is not null)
    {
        statusCodePagesFeature.Enabled = false;
    }
}

Kod för undantagshantering

Kod i undantagshanteringssidor kan också utlösa undantag. Sidor med produktionsfel bör testas noggrant och vara extra försiktiga för att undvika att själva ge upphov till undantag.

Svarshuvuden

När rubrikerna för ett svar har skickats:

  • Appen kan inte ändra svarets statuskod.
  • Undantagssidor eller hanterare kan inte köras. Svaret måste slutföras eller så avbryts anslutningen.

Hantering av serverfel

Förutom logiken för undantagshantering i en app kan HTTP-serverimplementering hantera vissa undantag. Om servern upptäcker ett undantag innan svarshuvuden skickas skickar servern ett 500 - Internal Server Error svar utan svarstext. Om servern stöter på ett undantag efter att svarshuvuden har skickats, stänger servern anslutningen. Begäranden som inte hanteras av appen hanteras av servern. Alla undantag som inträffar när servern hanterar begäran hanteras av serverns undantagshantering. Appens anpassade felsidor, undantagshantering av mellanprogram och filter påverkar inte det här beteendet.

Undantagshantering vid start

Endast värdlagret kan hantera undantag som sker under appstarten. Värden kan konfigureras för att fånga startfel och registrera detaljerade fel.

Värdlagret kan visa en felsida för ett insamlat startfel endast om felet inträffar efter värdadress/portbindning. Om bindningen misslyckas:

  • Värdlagret loggar ett kritiskt undantag.
  • DotNET-processen kraschar.
  • Ingen felsida visas när HTTP-servern är Kestrel.

När du kör på IIS (eller Azure App Service) eller IIS Expressreturneras en 502.5 – Processfel av ASP.NET Core-modulen om processen inte kan starta. Mer information finns i Felsöka ASP.NET Core i Azure App Service och IIS.

Sida med databasfel

Undantagsfiltret för databasutvecklare AddDatabaseDeveloperPageExceptionFilter samlar in databasrelaterade undantag som kan lösas med hjälp av Entity Framework Core-migreringar. När dessa undantag inträffar genereras ett HTML-svar med information om möjliga åtgärder för att lösa problemet. Den här sidan är endast aktiverad i utvecklingsmiljön. Följande kod lägger till ett undantagsfilter för sidan Databasutvecklare:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();

Undantagsfilter

I MVC-appar kan undantagsfilter konfigureras globalt eller per kontrollant eller per åtgärd. I Razor Pages-appar kan de konfigureras globalt eller per sidmodell. Dessa filter hanterar eventuella ohanterade undantag som inträffar under körningen av en kontrollåtgärd eller ett annat filter. Mer information finns i filter i ASP.NET Core.

Undantagsfilter är användbara för att fånga undantag som inträffar inom MVC-åtgärder, men de är inte lika flexibla som den inbyggda undantagshantering av mellanprogram, UseExceptionHandler. Vi rekommenderar att du använder UseExceptionHandler, såvida du inte behöver utföra felhantering på olika sätt baserat på vilken MVC-åtgärd som väljs.

Modelltillståndsfel

Information om hur du hanterar modelltillståndsfel finns i Modellbindning och modellverifiering.

Probleminformation

Probleminformation är inte det enda svarsformatet som beskriver ett HTTP API-fel, men de används ofta för att rapportera fel för HTTP-API:er.

Tjänsten probleminformation implementerar IProblemDetailsService-gränssnittet, som har stöd för att skapa probleminformation i ASP.NET Core. AddProblemDetails(IServiceCollection)-tilläggsmetoden på IServiceCollection registrerar standardimplementeringen IProblemDetailsService.

I ASP.NET Core-appar genererar följande mellanprogram probleminformation HTTP-svar när AddProblemDetails anropas, förutom när begäran om HTTP-header Accept inte innehåller någon av de innehållstyper som stöds av den registrerade IProblemDetailsWriter (standard: application/json):

Följande kod konfigurerar appen för att generera ett probleminformationssvar för alla HTTP-klient- och serverfelsvar som inte har något brödtextinnehåll ännu:

builder.Services.AddProblemDetails();

var app = builder.Build();        

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler();
    app.UseHsts();
}

app.UseStatusCodePages();

I nästa avsnitt visas hur du anpassar svarstexten för probleminformation.

Anpassa probleminformation

Automatisk skapande av en ProblemDetails kan anpassas med något av följande alternativ:

  1. Använd ProblemDetailsOptions.CustomizeProblemDetails
  2. Använd en anpassad IProblemDetailsWriter
  3. Anropa IProblemDetailsService i ett mellanprogram

CustomizeProblemDetails åtgärd

Den genererade probleminformationen kan anpassas med hjälp av CustomizeProblemDetailsoch anpassningarna tillämpas på all probleminformation som genereras automatiskt.

Följande kod använder ProblemDetailsOptions för att ange CustomizeProblemDetails:

builder.Services.AddProblemDetails(options =>
    options.CustomizeProblemDetails = ctx =>
            ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));

var app = builder.Build();        

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler();
    app.UseHsts();
}

app.UseStatusCodePages();

Ett HTTP Status 400 Bad Request slutpunktsresultat skapar till exempel följande svarstext för detaljer om problemet.

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "nodeId": "my-machine-name"
}

Anpassad IProblemDetailsWriter

En IProblemDetailsWriter implementering kan skapas för avancerade anpassningar.

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

Obs! När du använder en anpassad IProblemDetailsWritermåste den anpassade IProblemDetailsWriter registreras innan du anropar AddRazorPages, AddControllers, AddControllersWithViewseller 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();

Probleminformation från Middleware

Ett annat sätt att använda ProblemDetailsOptions med CustomizeProblemDetails är att ange ProblemDetails i mellanprogram. Ett probleminformationssvar kan skrivas genom att anropa IProblemDetailsService.WriteAsync:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseStatusCodePages();

// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
    await next(context);
    var mathErrorFeature = context.Features.Get<MathErrorFeature>();
    if (mathErrorFeature is not null)
    {
        if (context.RequestServices.GetService<IProblemDetailsService>() is
                                                           { } problemDetailsService)
        {
            (string Detail, string Type) details = mathErrorFeature.MathError switch
            {
                MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
                "https://en.wikipedia.org/wiki/Division_by_zero"),
                _ => ("Negative or complex numbers are not valid input.", 
                "https://en.wikipedia.org/wiki/Square_root")
            };

            await problemDetailsService.WriteAsync(new ProblemDetailsContext
            {
                HttpContext = context,
                ProblemDetails =
                {
                    Title = "Bad Input",
                    Detail = details.Detail,
                    Type = details.Type
                }
            });
        }
    }
});

// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
    if (denominator == 0)
    {
        var errorType = new MathErrorFeature { MathError =
                                               MathErrorType.DivisionByZeroError };
        context.Features.Set(errorType);
        return Results.BadRequest();
    }

    return Results.Ok(numerator / denominator);
});

// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
    if (radicand < 0)
    {
        var errorType = new MathErrorFeature { MathError =
                                               MathErrorType.NegativeRadicandError };
        context.Features.Set(errorType);
        return Results.BadRequest();
    }

    return Results.Ok(Math.Sqrt(radicand));
});

app.MapControllers();

app.Run();

I den föregående koden returnerar de minimala API-slutpunkterna /divide och /squareroot det förväntade anpassade problemsvaret för felindata.

API-kontrollantens slutpunkter returnerar standardfelsvaret vid felindata, inte det anpassade problemsvaret. Standardproblemsvaret returneras eftersom API-kontrollanten har skrivit till svarsströmmen Probleminformation för felstatuskoderinnan IProblemDetailsService.WriteAsync anropas och svaret inte skrivs igen.

Följande ValuesController returnerar BadRequestResult, som skriver till svarsströmmen och därför förhindrar att det anpassade problemsvaret returneras.

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

}

Följande Values3Controller returnerar ControllerBase.Problem så att det förväntade anpassade problemresultatet returneras:

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

}

Skapa en ProblemDetails-nyttolast för undantag

Tänk på följande app:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapControllers();
app.Run();

När ett undantag inträffar i icke-utvecklingsmiljöer är följande ett standardsvar ProblemDetails som returneras till klienten:

{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500,"traceId":"00-b644<snip>-00"
}

För de flesta appar är föregående kod allt som behövs för undantag. I följande avsnitt visas dock hur du får mer detaljerade problemsvar.

Ett alternativ till en anpassad undantagshanterarsida är att ange en lambda för UseExceptionHandler. Med hjälp av en lambda kan du komma åt felet och skriva ett probleminformationssvar med 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();

Varning

Ge inte känslig felinformation till klienter. Att servera fel är en säkerhetsrisk.

En annan metod för att generera probleminformation är att använda NuGet-paketet från tredje part Hellang.Middleware.ProblemDetails som kan användas för att mappa undantag och klientfel till probleminformation.

Ytterligare resurser

Av Tom Dykstra

Den här artikeln beskriver vanliga metoder för att hantera fel i ASP.NET Core-webbappar. Se även Hantera fel i ASP.NET Core-styrenhetsbaserade webb-API:er och Hantera fel i minimala API:er.

Undantagssida för utvecklare

utvecklarens undantagssida visar detaljerad information om ohanterade begäransundantag. ASP.NET Core-appar aktiverar utvecklarens undantagssida som standard när båda:

Undantagssidan för utvecklare körs tidigt i pipelinen för mellanprogram, så att den kan fånga ohanterade undantag som genereras i mellanprogram som följer.

Detaljerad undantagsinformation bör inte visas offentligt när appen körs i produktionsmiljön. Mer information om hur du konfigurerar miljöer finns i Använda flera miljöer i ASP.NET Core.

Sidan Undantag för utvecklare kan innehålla följande information om undantaget och begäran:

  • Stackspårning
  • Frågesträngsparametrar, om några
  • Cookies, om några
  • Rubriker

Undantagssidan för utvecklare är inte garanterad att ange någon information. Använd loggning för fullständig felinformation.

Sidan för undantagshanterare

Om du vill konfigurera en anpassad felhanteringssida för Produktionsmiljöanropar du UseExceptionHandler. Det här undantaget hanterar mellanprogram:

  • Fångar upp och loggar ohanterade undantag.
  • Utför begäran på nytt i en alternativ pipeline med den angivna sökvägen. Begäran körs inte igen när svaret har påbörjats. Den mallgenererade koden kör begäran igen via sökvägen /Error.

Varning

Om den alternativa pipelinen genererar ett eget undantag, återkastar undantagshanterings-mellanprogramvaran det ursprungliga undantaget.

Eftersom det här mellanprogrammet kan köra pipelinen för begäran igen:

  • Mellanprogram måste hantera återinträde med samma begäran. Detta innebär normalt antingen att de rensar upp sitt tillstånd efter att ha anropat _next eller cachelagrar bearbetningen på HttpContext för att undvika att göra om den. När du hanterar begärandetexten innebär detta antingen buffring eller cachelagring av resultat som formulärläsaren.
  • För den UseExceptionHandler(IApplicationBuilder, String)-överbelastning som används i mallar ändras endast sökvägen för begäran och routingsdata tas bort. Begärandedata som rubriker, metod och objekt återanvänds alla as-is.
  • Begränsade tjänster förblir desamma.

I följande exempel lägger UseExceptionHandler till undantagshanteringsmellanprogram i miljöer som inte är utvecklingsmiljöer:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Appmallen Razor Pages innehåller en felsida (.cshtml) och PageModel -klass (ErrorModel) i mappen Pages. För en MVC-app innehåller projektmallen en Error-åtgärdsmetod och en felvy för den Home kontrollanten.

Mellanprogrammet för undantagshantering utför begäran på nytt med hjälp av den ursprungliga HTTP-metoden. Om en slutpunkt för felhanterare är begränsad till en specifik uppsättning HTTP-metoder körs den endast för dessa HTTP-metoder. Till exempel körs en MVC-kontrollantåtgärd som använder attributet [HttpGet] endast för GET-begäranden. För att säkerställa att alla begäranden når sidan för anpassad felhantering ska du inte begränsa dem till en specifik uppsättning HTTP-metoder.

Så här hanterar du undantag på olika sätt baserat på den ursprungliga HTTP-metoden:

  • Skapa flera hanteringsmetoder för Razor Pages. Använd till exempel OnGet för att hantera GET-undantag och använda OnPost för att hantera POST-undantag.
  • För MVC använder du HTTP-verbattribut på flera åtgärder. Använd till exempel [HttpGet] för att hantera GET-undantag och använda [HttpPost] för att hantera POST-undantag.

Om du vill tillåta oautentiserade användare att visa sidan för anpassad felhantering kontrollerar du att den stöder anonym åtkomst.

Få åtkomst till undantaget

Använd IExceptionHandlerPathFeature för att komma åt undantaget och den ursprungliga sökvägen för begäran i en felhanterare. I följande exempel används IExceptionHandlerPathFeature för att få mer information om undantaget som utlöstes:

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

Varning

inte hantera känslig felinformation till klienter. Fel vid betjäning är en säkerhetsrisk.

Lambda-funktion för undantagshantering

Ett alternativ till en anpassad undantagshanterarsida är att ange en lambda för UseExceptionHandler. Med hjälp av en lambda kan du komma åt felet innan svaret returneras.

Följande kod använder en lambda för undantagshantering:

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

Varning

inte hantera känslig felinformation till klienter. Att skicka fel är en säkerhetsrisk.

AnvändStatusKodsSidor

Som standard tillhandahåller en ASP.NET Core-app inte någon statuskodsida för HTTP-felstatuskoder, till exempel 404 – Hittades inte. När appen anger en HTTP 400-599-felstatuskod som inte har någon brödtext returneras statuskoden och en tom svarstext. Om du vill aktivera standardhanterare med endast text för vanliga felstatuskoder anropar du UseStatusCodePages i Program.cs:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePages();

Anropa UseStatusCodePages innan du begär hantering av mellanprogram. Anropa till exempel UseStatusCodePages före mellanprogrammet för statiska filer och slutpunktsmellanprogrammet.

När UseStatusCodePages inte används returnerar navigering till en URL utan en slutpunkt ett webbläsarberoende felmeddelande som anger att slutpunkten inte kan hittas. När UseStatusCodePages anropas returnerar webbläsaren följande svar:

Status Code: 404; Not Found

UseStatusCodePages används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

Notera

Mellanprogrammet för statuskodsidor inte fånga undantag. Om du vill ange en anpassad sida för felhantering använder du undantagshanterarsidan .

UseStatusCodePages med formatsträng

Om du vill anpassa innehållstyp och text för svar, använder du överlagringen för UseStatusCodePages som accepterar en innehållstyp och formatsträng.

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

I föregående kod är {0} platshållare för felkoden.

UseStatusCodePages med en formatsträng används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

UseStatusCodePages med lambda

Om du vill ange anpassad felhanterings- och svarsskrivningskod använder du överlagringen av UseStatusCodePages som tar ett lambda-uttryck:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePages(async statusCodeContext =>
{
    // using static System.Net.Mime.MediaTypeNames;
    statusCodeContext.HttpContext.Response.ContentType = Text.Plain;

    await statusCodeContext.HttpContext.Response.WriteAsync(
        $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

UseStatusCodePages med en lambda används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

AnvändStatusKodssidorMedOmdirigeringar

Tilläggsmetoden UseStatusCodePagesWithRedirects:

  • Skickar en 302 – funnen statuskod till klienten.
  • Omdirigerar klienten till slutpunkten för felhantering som anges i URL-mallen. Slutpunkten för felhantering visar vanligtvis felinformation och returnerar HTTP 200.
var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

URL-mallen kan innehålla en {0}-platshållare för statuskoden, som visas i den föregående koden. Om URL-mallen börjar med ~ (tilde) ersätts ~ av appens PathBase. När du anger en slutpunkt i appen skapar du en MVC-vy eller Razor sida för slutpunkten.

Den här metoden används ofta när appen:

  • Ska omdirigera klienten till en annan slutpunkt, vanligtvis i fall där en annan app bearbetar felet. För webbappar återspeglar klientens webbläsaradressfält den omdirigerade slutpunkten.
  • Bör inte bevara och returnera den ursprungliga statuskoden med det första omdirigeringssvaret.

AnvändStatusKodSidorMedÅterKörning

Utökningsmetoden UseStatusCodePagesWithReExecute

  • Genererar svarstexten genom att köra begärandepipelinen igen med hjälp av en alternativ sökväg.
  • Ändrar inte statuskoden före eller efter att pipelinen körs om.

Den nya pipelinekörningen kan ändra svarets statuskod eftersom den nya pipelinen har fullständig kontroll över statuskoden. Om den nya pipelinen inte ändrar statuskoden skickas den ursprungliga statuskoden till klienten.

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");

Om en slutpunkt i appen har angetts skapar du en MVC-vy eller Razor sida för slutpunkten.

Den här metoden används ofta när appen ska:

  • Bearbeta begäran utan att omdirigera till en annan slutpunkt. För webbappar återspeglar klientens webbläsaradressfält den ursprungligen begärda slutpunkten.
  • Bevara och returnera den ursprungliga statuskoden med svaret.

URL-mallen måste börja med / och kan innehålla en platshållare {0} för statuskoden. Skicka statuskoden som en frågesträngsparameter genom att skicka ett andra argument till UseStatusCodePagesWithReExecute. Till exempel:

var app = builder.Build();  
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");

Slutpunkten som bearbetar felet kan hämta den ursprungliga URL:en som genererade felet, enligt följande exempel:

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

        }
    }
}

Eftersom det här mellanprogrammet kan köra pipelinen för begäran igen:

  • Mellanprogram måste hantera återaktivering med samma begäran. Detta innebär normalt antingen att de rensar upp sitt tillstånd efter att ha anropat _next eller cachelagrar bearbetningen på HttpContext för att undvika att göra om den. När du hanterar begärandetexten innebär detta antingen buffring eller cachelagring av resultat som formulärläsaren.
  • Begränsade tjänster förblir desamma.

Inaktivera statuskodsidor

Om du vill inaktivera statuskodsidor för en MVC-kontrollant eller åtgärdsmetod använder du attributet [SkipStatusCodePages].

Om du vill inaktivera statuskodsidor för specifika begäranden i en Razor Pages-hanteringsmetod eller i en MVC-styrenhet använder du IStatusCodePagesFeature:

public void OnGet()
{
    var statusCodePagesFeature =
        HttpContext.Features.Get<IStatusCodePagesFeature>();

    if (statusCodePagesFeature is not null)
    {
        statusCodePagesFeature.Enabled = false;
    }
}

Kod för undantagshantering

Kod i undantagshanteringssidor kan också utlösa undantag. Sidor med produktionsfel bör testas noggrant och vara extra noggranna för att undvika egna undantag.

Response headers

När rubrikerna för ett svar har skickats:

  • Appen kan inte ändra svarets statuskod.
  • Undantagssidor eller hanterare kan inte köras. Svaret måste slutföras eller så avbryts anslutningen.

Hantering av serverfel

Förutom logiken för undantagshantering i en app kan HTTP-serverimplementering hantera vissa undantag. Om servern upptäcker ett undantag innan svarshuvuden skickas skickar servern ett 500 - Internal Server Error svar utan svarstext. Om servern får ett undantag när svarshuvuden har skickats stänger servern anslutningen. Begäranden som inte hanteras av appen hanteras av servern. Alla undantag som inträffar när servern hanterar begäran hanteras av serverns undantagshantering. Appens anpassade felsidor, undantagshantering av mellanprogram och filter påverkar inte det här beteendet.

Undantagshantering vid start

Endast värdlagret kan hantera undantag som sker under appstarten. Värden kan konfigureras för att fånga startfel och fånga detaljerade fel.

Värdlagret kan visa en felsida för ett insamlat startfel endast om felet inträffar efter värdadress/portbindning. Om bindningen misslyckas:

  • Värdlagret loggar ett kritiskt undantag.
  • Dotnet-processen kraschar.
  • Ingen felsida visas när HTTP-servern är Kestrel.

När du kör på IIS (eller Azure App Service) eller IIS Expressreturneras en 502.5 – Processfel av ASP.NET Core-modulen om processen inte kan starta. Mer information finns i Felsöka ASP.NET Core i Azure App Service och IIS.

Sida för databasfel

Undantagsfiltret för databasutvecklare AddDatabaseDeveloperPageExceptionFilter samlar in databasrelaterade undantag som kan lösas med hjälp av Entity Framework Core-migreringar. När dessa undantag inträffar genereras ett HTML-svar med information om möjliga åtgärder för att lösa problemet. Den här sidan är endast aktiverad i utvecklingsmiljön. Följande kod lägger till undantagsfiltret på sidan för databasutvecklare:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();

Undantagsfilter

I MVC-appar kan undantagsfilter konfigureras globalt eller per kontrollant eller per åtgärd. I Razor Pages-appar kan de konfigureras globalt eller per sidmodell. Dessa filter hanterar eventuella ohanterade undantag som inträffar när en kontrollantåtgärd eller ett annat filter körs. Mer information finns i filter i ASP.NET Core.

Undantagsfilter är användbara för att fånga undantag som inträffar inom MVC-åtgärder, men de är inte lika flexibla som den inbyggda undantagshantering av mellanprogram, UseExceptionHandler. Vi rekommenderar att du använder UseExceptionHandler, såvida du inte behöver utföra felhantering på olika sätt baserat på vilken MVC-åtgärd som väljs.

Modelltillståndsfel

Information om hur du hanterar modelltillståndsfel finns i Modellbindning och modellverifiering.

Probleminformation

Probleminformation är inte det enda svarsformatet som beskriver ett HTTP API-fel, men de används ofta för att rapportera fel för HTTP-API:er.

Tjänsten probleminformation implementerar IProblemDetailsService-gränssnittet, som har stöd för att skapa probleminformation i ASP.NET Core. AddProblemDetails(IServiceCollection)-tilläggsmetoden på IServiceCollection registrerar standardimplementeringen IProblemDetailsService.

I ASP.NET Core-appar genererar följande mellanmjukvara problemdetaljer HTTP-svar när AddProblemDetails anropas, förutom när begäran Accept med HTTP-huvudet inte innehåller någon av de innehållstyper som stöds av den registrerade IProblemDetailsWriter (standard: application/json).

Följande kod konfigurerar appen för att generera ett probleminformationssvar för alla HTTP-klient- och serverfelsvar som inte har något brödtextinnehåll ännu:

builder.Services.AddProblemDetails();

var app = builder.Build();        

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler();
    app.UseHsts();
}

app.UseStatusCodePages();

I nästa avsnitt visas hur du anpassar svarstexten för probleminformation.

Anpassa probleminformation

Automatisk skapande av en ProblemDetails kan anpassas med något av följande alternativ:

  1. Använd ProblemDetailsOptions.CustomizeProblemDetails
  2. Använd en anpassad IProblemDetailsWriter
  3. Anropa IProblemDetailsService i ett mellanprogram

CustomizeProblemDetails åtgärd

Den genererade probleminformationen kan anpassas med hjälp av CustomizeProblemDetailsoch anpassningarna tillämpas på all probleminformation som genereras automatiskt.

Följande kod använder ProblemDetailsOptions för att ange CustomizeProblemDetails:

builder.Services.AddProblemDetails(options =>
    options.CustomizeProblemDetails = ctx =>
            ctx.ProblemDetails.Extensions.Add("nodeId", Environment.MachineName));

var app = builder.Build();        

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler();
    app.UseHsts();
}

app.UseStatusCodePages();

Ett HTTP Status 400 Bad Request slutpunktsresultat skapar till exempel följande svarstext för probleminformation:

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "nodeId": "my-machine-name"
}

Anpassad IProblemDetailsWriter

En IProblemDetailsWriter implementering kan skapas för avancerade anpassningar.

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

Obs! När du använder en anpassad IProblemDetailsWritermåste den anpassade IProblemDetailsWriter registreras innan du anropar AddRazorPages, AddControllers, AddControllersWithViewseller 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();

Probleminformation från Middleware

Ett annat sätt att använda ProblemDetailsOptions med CustomizeProblemDetails är att ange ProblemDetails i mellanprogram. Ett probleminformationssvar kan skrivas genom att anropa IProblemDetailsService.WriteAsync:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseStatusCodePages();

// Middleware to handle writing problem details to the response.
app.Use(async (context, next) =>
{
    await next(context);
    var mathErrorFeature = context.Features.Get<MathErrorFeature>();
    if (mathErrorFeature is not null)
    {
        if (context.RequestServices.GetService<IProblemDetailsService>() is
                                                           { } problemDetailsService)
        {
            (string Detail, string Type) details = mathErrorFeature.MathError switch
            {
                MathErrorType.DivisionByZeroError => ("Divison by zero is not defined.",
                "https://en.wikipedia.org/wiki/Division_by_zero"),
                _ => ("Negative or complex numbers are not valid input.", 
                "https://en.wikipedia.org/wiki/Square_root")
            };

            await problemDetailsService.WriteAsync(new ProblemDetailsContext
            {
                HttpContext = context,
                ProblemDetails =
                {
                    Title = "Bad Input",
                    Detail = details.Detail,
                    Type = details.Type
                }
            });
        }
    }
});

// /divide?numerator=2&denominator=4
app.MapGet("/divide", (HttpContext context, double numerator, double denominator) =>
{
    if (denominator == 0)
    {
        var errorType = new MathErrorFeature { MathError =
                                               MathErrorType.DivisionByZeroError };
        context.Features.Set(errorType);
        return Results.BadRequest();
    }

    return Results.Ok(numerator / denominator);
});

// /squareroot?radicand=16
app.MapGet("/squareroot", (HttpContext context, double radicand) =>
{
    if (radicand < 0)
    {
        var errorType = new MathErrorFeature { MathError =
                                               MathErrorType.NegativeRadicandError };
        context.Features.Set(errorType);
        return Results.BadRequest();
    }

    return Results.Ok(Math.Sqrt(radicand));
});

app.MapControllers();

app.Run();

I den föregående koden returnerar de minimala API-slutpunkterna /divide och /squareroot det förväntade anpassade problemsvaret vid felindata.

API-kontrollantens slutpunkter returnerar standardfelsvaret vid felindata, inte det anpassade problemsvaret. Standardproblemsvaret returneras eftersom API-kontrollanten har skrivit till svarsströmmen Probleminformation för felstatuskoderinnan IProblemDetailsService.WriteAsync anropas och svaret inte skrivs igen.

Följande ValuesController returnerar BadRequestResult, vilket skriver till svarsströmmen och därför förhindrar att det anpassade problemsvaret returneras.

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

}

Följande Values3Controller returnerar ControllerBase.Problem så att det förväntade anpassade problemresultatet returneras:

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

}

Skapa en ProblemDetails-nyttolast för undantag

Tänk på följande app:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapControllers();
app.Run();

När ett undantag inträffar i icke-utvecklingsmiljöer är följande ett standardsvar ProblemDetails som returneras till klienten:

{
"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title":"An error occurred while processing your request.",
"status":500,"traceId":"00-b644<snip>-00"
}

För de flesta appar är föregående kod allt som behövs för undantag. I följande avsnitt visas dock hur du får mer detaljerade problemsvar.

Ett alternativ till en anpassad undantagshanterarsida är att ange en lambda för UseExceptionHandler. Med hjälp av en lambda kan du komma åt felet och skriva ett probleminformationssvar med 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();

Varning

Servera inte känslig felinformation till klienter. Att hantera fel är en säkerhetsrisk.

En annan metod för att generera probleminformation är att använda NuGet-paketet från tredje part Hellang.Middleware.ProblemDetails som kan användas för att mappa undantag och klientfel till probleminformation.

Ytterligare resurser

Av Tom Dykstra

Den här artikeln beskriver vanliga metoder för att hantera fel i ASP.NET Core-webbappar. Se Hantera fel i ASP.NET Core-styrenhetsbaserade webb-API:er för webb-API:er.

Undantagssida för utvecklare

Utvecklarundantagssidan visar detaljerad information om ohanterade undantag för förfrågningar. ASP.NET Core-appar aktiverar utvecklarens undantagssida som standard när båda:

Undantagssidan för utvecklare körs tidigt i mellanprogramspipelinen, så att den kan fånga ohanterade undantag som kastas i efterföljande mellanprogram.

Detaljerad undantagsinformation bör inte visas offentligt när appen körs i produktionsmiljön. Mer information om hur du konfigurerar miljöer finns i Använda flera miljöer i ASP.NET Core.

Sidan Undantag för utvecklare kan innehålla följande information om undantaget och begäran:

  • Stackspårning
  • Frågesträngsparametrar, om några
  • Cookies, om några
  • Rubriker

Undantagssidan för utvecklare är inte garanterad att ange någon information. Använd loggning för fullständig felinformation.

Undantagshanterarsidan

Om du vill konfigurera en anpassad felhanteringssida för Produktionsmiljöanropar du UseExceptionHandler. Det här undantaget hanterar mellanprogram:

  • Fångar upp och loggar ohanterade undantag.
  • Kör begäran igen i en alternativ pipeline med den sökväg som anges. Begäran utförs inte på nytt om svaret har påbörjats. Den mallgenererade koden kör begäran igen med hjälp av sökvägen /Error.

Varning

Om den alternativa pipelinen genererar ett eget undantag, kastar Undantagshanterings-mellanprogrammet om det ursprungliga undantaget.

I följande exempel lägger UseExceptionHandler till undantagshanteringsmellanprogram i miljöer som inte är utvecklingsmiljöer:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Appmallen Razor Pages innehåller en felsida (.cshtml) och PageModel -klass (ErrorModel) i mappen Pages. För en MVC-app innehåller projektmallen en Error-åtgärdsmetod och en felvy för den Home kontrollanten.

Undantagshanteringsmiddleware kör om begäran och använder den ursprungliga HTTP-metoden. Om en slutpunkt för felhanterare är begränsad till en specifik uppsättning HTTP-metoder körs den endast för dessa HTTP-metoder. Till exempel körs en MVC-kontrollantåtgärd som använder attributet [HttpGet] endast för GET-begäranden. För att säkerställa att alla begäranden når sidan för anpassad felhantering ska du inte begränsa dem till en specifik uppsättning HTTP-metoder.

Så här hanterar du undantag på olika sätt baserat på den ursprungliga HTTP-metoden:

  • Skapa flera hanteringsmetoder för Razor Pages. Använd till exempel OnGet för att hantera GET-undantag och använda OnPost för att hantera POST-undantag.
  • För MVC använder du HTTP-verbattribut på flera åtgärder. Använd till exempel [HttpGet] för att hantera GET-undantag och använda [HttpPost] för att hantera POST-undantag.

Om du vill tillåta oautentiserade användare att visa sidan för anpassad felhantering kontrollerar du att den stöder anonym åtkomst.

Få åtkomst till undantaget

Använd IExceptionHandlerPathFeature för att komma åt undantaget och den ursprungliga sökvägen för begäran i en felhanterare. I följande exempel används IExceptionHandlerPathFeature för att få mer information om undantaget som utlöstes:

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

Varning

inte hantera känslig felinformation till klienter. Att hantera fel är en säkerhetsrisk.

Lambda för undantagshantering

Ett alternativ till en anpassad undantagshanterarsida är att ange en lambda för UseExceptionHandler. Med hjälp av en lambda kan du komma åt felet innan svaret returneras.

Följande kod använder en lambda för undantagshantering:

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

Varning

inte hantera känslig felinformation till klienter. Att leverera fel är en säkerhetsrisk.

AnvändStatusKodSidor

Som standard tillhandahåller en ASP.NET Core-app inte någon statuskodsida för HTTP-felstatuskoder, till exempel 404 – Hittades inte. När appen anger en HTTP 400-599-felstatuskod som inte har någon brödtext returneras statuskoden och en tom svarstext. Om du vill aktivera standardhanterare med endast text för vanliga felstatuskoder anropar du UseStatusCodePages i Program.cs:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePages();

Anropa UseStatusCodePages innan du begär hantering av mellanprogram. Till exempel, ring UseStatusCodePages före det statiska filmellanprogrammet och slutpunktmellanprogrammet.

När UseStatusCodePages inte används returnerar navigering till en URL utan en slutpunkt ett webbläsarberoende felmeddelande som anger att slutpunkten inte kan hittas. När UseStatusCodePages anropas returnerar webbläsaren följande svar:

Status Code: 404; Not Found

UseStatusCodePages används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

Not

Mellanprogrammet för statuskodsidor inte fånga undantag. För att tillhandahålla en anpassad undantagshanteringssida, använd sidan .

UseStatusCodePages som använder en formatsträng

Om du vill anpassa svarsinnehållstypen och texten använder du överlagringen av UseStatusCodePages som tar en innehållstyp och formatsträng:

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

I föregående kod är {0} platshållare för felkoden.

UseStatusCodePages med en formatsträng används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

UseStatusCodePages med lambda

För att ange anpassad kod för felhantering och svarsskrivning, använd den överlagrade metoden UseStatusCodePages som tar ett lambda-uttryck.

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePages(async statusCodeContext =>
{
    // using static System.Net.Mime.MediaTypeNames;
    statusCodeContext.HttpContext.Response.ContentType = Text.Plain;

    await statusCodeContext.HttpContext.Response.WriteAsync(
        $"Status Code Page: {statusCodeContext.HttpContext.Response.StatusCode}");
});

UseStatusCodePages med en lambda används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

AnvändStatuskodsSidorMedOmdirigeringar

Tilläggsmetoden UseStatusCodePagesWithRedirects

  • Skickar en 302 – Hittade statuskod till klienten.
  • Omdirigerar klienten till slutpunkten för felhantering som anges i URL-mallen. Slutpunkten för felhantering visar vanligtvis felinformation och returnerar HTTP 200.
var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePagesWithRedirects("/StatusCode/{0}");

URL-mallen kan innehålla en {0} platshållare för statuskoden, enligt föregående kod. Om URL-mallen börjar med ~ (tilde) ersätts ~ av appens PathBase. När du anger en slutpunkt i appen skapar du en MVC-vy eller Razor sida för slutpunkten.

Den här metoden används ofta när appen:

  • Ska omdirigera klienten till en annan slutpunkt, vanligtvis i fall där en annan app bearbetar felet. För webbappar återspeglar klientens webbläsaradressfält den omdirigerade slutpunkten.
  • Bör inte bevara och returnera den ursprungliga statuskoden med det första omdirigeringssvaret.

AnvändStatusCodeSidorMedÅterkörning

Utökningsmetod UseStatusCodePagesWithReExecute

  • Returnerar den ursprungliga statuskoden till klienten.
  • Genererar svarstexten genom att köra begärandepipelinen igen med hjälp av en alternativ sökväg.
var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStatusCodePagesWithReExecute("/StatusCode/{0}");

Om en slutpunkt i appen har angetts skapar du en MVC-vy eller Razor sida för slutpunkten.

Den här metoden används ofta när appen ska:

  • Bearbeta begäran utan att omdirigera till en annan slutpunkt. För webbappar återspeglar klientens webbläsaradressfält den ursprungligen begärda slutpunkten.
  • Bevara och returnera den ursprungliga statuskoden med svaret.

URL-mallen måste börja med / och kan innehålla en platshållare {0} för statuskoden. Skicka statuskoden som en frågesträngsparameter genom att skicka ett andra argument till UseStatusCodePagesWithReExecute. Till exempel:

app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");

Slutpunkten som bearbetar felet kan hämta den ursprungliga URL:en som genererade felet, enligt följande exempel:

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

Inaktivera statuskodsidor

Om du vill inaktivera statuskodsidor för en MVC-kontrollant eller åtgärdsmetod använder du attributet [SkipStatusCodePages].

Om du vill inaktivera statuskodsidor för specifika begäranden i en Razor Pages-hanteringsmetod eller i en MVC-styrenhet använder du IStatusCodePagesFeature:

public void OnGet()
{
    var statusCodePagesFeature =
        HttpContext.Features.Get<IStatusCodePagesFeature>();

    if (statusCodePagesFeature is not null)
    {
        statusCodePagesFeature.Enabled = false;
    }
}

Kod för undantagshantering

Kod i undantagshanteringssidor kan också utlösa undantag. Sidor med produktionsfel bör testas noggrant och vara extra noggranna för att undvika egna undantag.

Svarshuvuden

När rubrikerna för ett svar har skickats:

  • Appen kan inte ändra svarets statuskod.
  • Undantagssidor eller hanterare kan inte köras. Svaret måste slutföras eller så avbryts anslutningen.

Hantering av serverfel

Förutom logiken för undantagshantering i en app kan HTTP-serverimplementering hantera vissa undantag. Om servern upptäcker ett undantag innan svarshuvuden skickas skickar servern ett 500 - Internal Server Error svar utan svarstext. Om servern får ett undantag när svarshuvuden har skickats stänger servern anslutningen. Begäranden som inte hanteras av appen hanteras av servern. Alla undantag som inträffar när servern hanterar begäran hanteras av serverns undantagshantering. Appens anpassade felsidor, undantagshantering av mellanprogram och filter påverkar inte det här beteendet.

Undantagshantering vid start

Endast värdlagret kan hantera undantag som sker under appstarten. Värden kan konfigureras för att fånga startfel och fånga detaljerade fel.

Värdlagret kan visa en felsida för ett insamlat startfel endast om felet inträffar efter värdadress/portbindning. Om bindningen misslyckas:

  • Värdlagret loggar ett kritiskt undantagsfel.
  • Dotnet-processen kraschar.
  • Ingen felsida visas när HTTP-servern är Kestrel.

När du kör på IIS (eller Azure App Service) eller IIS Expressreturneras en 502.5 – Processfel av ASP.NET Core-modulen om processen inte kan starta. Mer information finns i Felsöka ASP.NET Core i Azure App Service och IIS.

Databasfelssida

Undantagsfiltret för databasutvecklare AddDatabaseDeveloperPageExceptionFilter samlar in databasrelaterade undantag som kan lösas med hjälp av Entity Framework Core-migreringar. När dessa undantag inträffar genereras ett HTML-svar med information om möjliga åtgärder för att lösa problemet. Den här sidan är endast aktiverad i utvecklingsmiljön. Följande kod lägger till undantagsfiltret för databasutvecklarsidan:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddRazorPages();

Undantagsfilter

I MVC-appar kan undantagsfilter konfigureras globalt eller per kontrollant eller per åtgärd. I Razor Pages-appar kan de konfigureras globalt eller per sidmodell. Dessa filter hanterar alla ohanterade undantag som inträffar under körningen av en kontrolleråtgärd eller ett annat filter. Mer information finns i filter i ASP.NET Core.

Undantagsfilter är användbara för att fånga undantag som inträffar inom MVC-åtgärder, men de är inte lika flexibla som den inbyggda undantagshanteringsmiddleware, UseExceptionHandler. Vi rekommenderar att du använder UseExceptionHandler, såvida du inte behöver utföra felhantering på olika sätt baserat på vilken MVC-åtgärd som väljs.

Modelltillståndsfel

Information om hur du hanterar modelltillståndsfel finns i Modellbindning och modellverifiering.

Ytterligare resurser

Av Kirk Larkin, Tom Dykstraoch Steve Smith

Den här artikeln beskriver vanliga metoder för att hantera fel i ASP.NET Core-webbappar. Se Hantera fel i ASP.NET Core-styrenhetsbaserade webb-API:er för webb-API:er.

Visa eller ladda ned exempelkod. (Ladda ned.) Fliken Nätverk i utvecklarverktygen för F12-webbläsaren är användbar när du testar exempelappen.

Undantagssida för utvecklare

undantagssidan för utvecklare visar detaljerad information om ohanterade undantag för begäranden. Mallarna ASP.NET Core genererar följande kod:

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

Den föregående markerade koden aktiverar undantagssidan för utvecklare när appen körs i Utvecklingsmiljö.

Mallarna placerar UseDeveloperExceptionPage tidigt i pipelinen för mellanprogram så att de kan fånga ohanterade undantag som genereras i mellanprogram som följer.

Föregående kod aktiverar sidan Undantag för utvecklare endast när appen körs i utvecklingsmiljön. Detaljerad undantagsinformation bör inte visas offentligt när appen körs i produktionsmiljön. Mer information om hur du konfigurerar miljöer finns i Använda flera miljöer i ASP.NET Core.

Sidan Undantag för utvecklare kan innehålla följande information om undantaget och begäran:

  • Stackspårning
  • Frågesträngsparametrar, om det finns några
  • Eventuella cookies
  • Rubriker

Undantagssidan för utvecklare är inte garanterad att ange någon information. Använd Loggning för att få fullständig felinformation.

Undantagshanterarsida

Om du vill konfigurera en anpassad felhanteringssida för Produktionsmiljöanropar du UseExceptionHandler. Denna middleware för undantagshantering:

  • Fångar upp och loggar ohanterade undantag.
  • Kör begäran igen i en alternativ pipeline med den sökväg som anges. Begäran exekveras inte på nytt om svaret redan har startats. Den mallgenererade koden utför begäran på nytt genom sökvägen /Error.

Varning

Om den alternativa pipelinen genererar ett eget undantag, kastar Undantagshanteringsmellanprogrammet om det ursprungliga undantaget.

I följande exempel lägger UseExceptionHandler till undantagshanteringsmellanprogram i miljöer som inte är utvecklingsmiljöer:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Appmallen Razor Pages innehåller en felsida (.cshtml) och PageModel -klass (ErrorModel) i mappen Pages. För en MVC-app innehåller projektmallen en Error-åtgärdsmetod och en felvy för den Home kontrollanten.

Undantaget hantering av mellanprogram kör begäran igen med hjälp av den ursprungliga HTTP-metoden. Om en slutpunkt för felhanterare är begränsad till en specifik uppsättning HTTP-metoder körs den endast för dessa HTTP-metoder. Till exempel körs en MVC-kontrollantåtgärd som använder attributet [HttpGet] endast för GET-begäranden. För att säkerställa att alla begäranden når sidan för anpassad felhantering ska du inte begränsa dem till en specifik uppsättning HTTP-metoder.

Så här hanterar du undantag på olika sätt baserat på den ursprungliga HTTP-metoden:

  • Skapa flera hanteringsmetoder för Razor Pages. Använd till exempel OnGet för att hantera GET-undantag och använda OnPost för att hantera POST-undantag.
  • För MVC använder du HTTP-verbattribut på flera åtgärder. Använd till exempel [HttpGet] för att hantera GET-undantag och använda [HttpPost] för att hantera POST-undantag.

Om du vill tillåta oautentiserade användare att visa sidan för anpassad felhantering kontrollerar du att den stöder anonym åtkomst.

Få åtkomst till undantaget

Använd IExceptionHandlerPathFeature för att komma åt undantaget och den ursprungliga sökvägen för begäran i en felhanterare. Följande kod lägger till ExceptionMessage till standard Pages/Error.cshtml.cs som genereras av ASP.NET Core-mallarna:

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

Varning

inte hantera känslig felinformation till klienter. Att leverera fel är en säkerhetsrisk.

Testa undantaget i exempelappen:

  • Ställ in miljön på produktionsläge.
  • Ta bort kommentarerna från webBuilder.UseStartup<Startup>(); i Program.cs.
  • Välj Utlösa ett undantag på sidan home.

Lambda för undantagshanterare

Ett alternativ till en anpassad undantagshanterarsida är att ange en lambda för UseExceptionHandler. Med hjälp av en lambda kan du komma åt felet innan svaret returneras.

Följande kod använder en lambda för undantagshantering:

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

Varning

Skicka inte känslig felinformation från IExceptionHandlerFeature eller IExceptionHandlerPathFeature till klienter. Att skicka felmeddelanden är en säkerhetsrisk.

Testa undantagshanteringen av lambda i exempelappen:

  • Ange miljön som produktion.
  • Ta bort kommentarerna från webBuilder.UseStartup<StartupLambda>(); i Program.cs.
  • Välj Utlösa ett undantag på sidan home.

AnvändStatusKodSidor

Som standard tillhandahåller en ASP.NET Core-app inte någon statuskodsida för HTTP-felstatuskoder, till exempel 404 – Hittades inte. När appen anger en HTTP 400-599-felstatuskod som inte har någon brödtext returneras statuskoden och en tom svarstext. Om du vill ange statuskodsidor använder du mellanprogrammet för statuskodsidor. Om du vill aktivera standardhanterare med endast text för vanliga felstatuskoder anropar du UseStatusCodePages i metoden Startup.Configure:

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

Anropa UseStatusCodePages innan du begär hantering av mellanprogram. Anropa till exempel UseStatusCodePages före medelprogrammet för statiska filer och medelprogrammet för slutpunkter.

När UseStatusCodePages inte används returnerar navigering till en URL utan en slutpunkt ett webbläsarberoende felmeddelande som anger att slutpunkten inte kan hittas. Du kan till exempel navigera till Home/Privacy2. När UseStatusCodePages anropas returnerar webbläsaren:

Status Code: 404; Not Found

UseStatusCodePages används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

Testa UseStatusCodePages i exempelappen:

  • Ställ in miljön till produktion.
  • Ta bort kommentarerna från webBuilder.UseStartup<StartupUseStatusCodePages>(); i Program.cs.
  • Välj länkarna på sidan home på sidan home.

Notis

Mellanprogrammet för statuskodsidor inte fånga undantag. För att ange en anpassad felhanteringssida, använd undantagshanterarsidan .

UseStatusCodePages med formatsträng

Om du vill anpassa svarsinnehållstypen och texten använder du överlagringen av UseStatusCodePages som tar en innehållstyp och formatsträng:

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

I föregående kod är {0} en platshållare för felkoden.

UseStatusCodePages med en formatsträng används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

Om du vill testa UseStatusCodePages i exempelappentar du bort kommentarerna från webBuilder.UseStartup<StartupFormat>(); i Program.cs.

UseStatusCodePages med lambda

För att ange anpassad felhanterings- och svarsskrivningskod använder du en överlagring av UseStatusCodePages som tar ett lambda-uttryck.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

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

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

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

UseStatusCodePages med en lambda används vanligtvis inte i produktion eftersom det returnerar ett meddelande som inte är användbart för användarna.

Om du vill testa UseStatusCodePages i exempelappentar du bort kommentarerna från webBuilder.UseStartup<StartupStatusLambda>(); i Program.cs.

AnvändStatuskodSidorMedOmdirigeringar

UseStatusCodePagesWithRedirects-tilläggsmetoden:

  • Skickar en 302 – Hittade statuskod till klienten.
  • Omdirigerar klienten till slutpunkten för felhantering som anges i URL-mallen. Slutpunkten för felhantering visar vanligtvis felinformation och returnerar HTTP 200.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseStatusCodePagesWithRedirects("/MyStatusCode?code={0}");

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

URL-mallen kan innehålla en {0}-platshållare för statuskoden, som visas i föregående kod. Om URL-mallen börjar med ~ (tilde) ersätts ~ av appens PathBase. När du anger en slutpunkt i appen skapar du en MVC-vy eller Razor sida för slutpunkten. Ett Razor pages-exempel finns i Pages/MyStatusCode.cshtml i exempelappen .

Den här metoden används ofta när appen:

  • Ska omdirigera klienten till en annan slutpunkt, vanligtvis i fall där en annan app bearbetar felet. För webbappar återspeglar klientens webbläsaradressfält den omdirigerade slutpunkten.
  • Bör inte bevara och returnera den ursprungliga statuskoden med det första omdirigeringssvaret.

Om du vill testa UseStatusCodePages i exempelappentar du bort kommentarerna från webBuilder.UseStartup<StartupSCredirect>(); i Program.cs.

Använd statuskodsidor med ReExecute

Utökningsmetoden UseStatusCodePagesWithReExecute:

  • Returnerar den ursprungliga statuskoden till klienten.
  • Genererar svarstexten genom att köra begärandepipelinen igen med hjälp av en alternativ sökväg.
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();
    });
}

Om en slutpunkt i appen har angetts skapar du en MVC-vy eller Razor sida för slutpunkten. Kontrollera att UseStatusCodePagesWithReExecute placeras före UseRouting så att begäran kan omdirigeras till statussidan. Ett Razor pages-exempel finns i Pages/MyStatusCode2.cshtml i exempelappen .

Den här metoden används ofta när appen ska:

  • Bearbeta begäran utan att omdirigera till en annan slutpunkt. För webbappar återspeglar klientens webbläsaradressfält den ursprungligen begärda slutpunkten.
  • Bevara och returnera den ursprungliga statuskoden med svaret.

URL- och frågesträngsmallar kan innehålla en platshållare {0} för statuskod. URL-mallen måste börja med /.

Slutpunkten som bearbetar felet kan hämta den ursprungliga URL:en som genererade felet, enligt följande exempel:

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

Ett Razor pages-exempel finns i Pages/MyStatusCode2.cshtml i exempelappen .

Om du vill testa UseStatusCodePages i exempelappentar du bort kommentarerna från webBuilder.UseStartup<StartupSCreX>(); i Program.cs.

Inaktivera statuskodsidor

Om du vill inaktivera statuskodsidor för en MVC-kontrollant eller åtgärdsmetod använder du attributet [SkipStatusCodePages].

Om du vill inaktivera statuskodsidor för specifika begäranden i en Razor Pages-hanteringsmetod eller i en MVC-styrenhet använder du IStatusCodePagesFeature:

public void OnGet()
{
    // using Microsoft.AspNetCore.Diagnostics;
    var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();

    if (statusCodePagesFeature != null)
    {
        statusCodePagesFeature.Enabled = false;
    }
}

Kod för undantagshantering

Kod i undantagshanteringssidor kan också utlösa undantag. Sidor med produktionsfel bör testas noggrant och vara extra noggranna för att undvika egna undantag.

Svarshuvuden

När rubrikerna för ett svar har skickats:

  • Appen kan inte ändra svarets statuskod.
  • Undantagssidor eller hanterare kan inte köras. Svaret måste slutföras eller så avbryts anslutningen.

Hantering av serverfel

Förutom logiken för undantagshantering i en app kan HTTP-serverimplementering hantera vissa undantag. Om servern upptäcker ett undantag innan svarshuvuden skickas skickar servern ett 500 - Internal Server Error svar utan svarstext. Om servern får ett undantag när svarshuvuden har skickats stänger servern anslutningen. Begäranden som inte hanteras av appen hanteras av servern. Alla undantag som inträffar när servern hanterar begäran hanteras av serverns undantagshantering. Appens anpassade felsidor, undantagshantering av mellanprogram och filter påverkar inte det här beteendet.

Undantagshantering vid start

Endast värdlagret kan hantera undantag som sker under appstarten. Värden kan konfigureras för att fånga startfel och fånga detaljerade fel.

Värdlagret kan visa en felsida för ett insamlat startfel endast om felet inträffar efter värdadress/portbindning. Om bindningen misslyckas:

  • Värdlagret loggar ett kritiskt fel.
  • Dotnet-processen kraschar.
  • Ingen felsida visas när HTTP-servern är Kestrel.

När du kör på IIS (eller Azure App Service) eller IIS Expressreturneras en 502.5 – Processfel av ASP.NET Core-modulen om processen inte kan starta. Mer information finns i Felsöka ASP.NET Core i Azure App Service och IIS.

Sidan databasfel

Undantagsfiltret för databasutvecklare AddDatabaseDeveloperPageExceptionFilter samlar in databasrelaterade undantag som kan lösas med hjälp av Entity Framework Core-migreringar. När dessa undantag inträffar genereras ett HTML-svar med information om möjliga åtgärder för att lösa problemet. Den här sidan är endast aktiverad i utvecklingsmiljön. Följande kod genererades av mallarna ASP.NET Core Razor Pages när enskilda användarkonton angavs:

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

Undantagsfilter

I MVC-appar kan undantagsfilter konfigureras globalt eller per kontrollant eller per åtgärd. I Razor Pages-appar kan de konfigureras globalt eller per sidmodell. Dessa filter hanterar alla ohanterade undantag som inträffar under körningen av en kontrolleråtgärd eller ett annat filter. Mer information finns i filter i ASP.NET Core.

Undantagsfilter är användbara för att fånga undantag som inträffar inom MVC-åtgärder, men de är inte lika flexibla som den inbyggda undantagshanterings-mellanvara, UseExceptionHandler. Vi rekommenderar att du använder UseExceptionHandler, såvida du inte behöver utföra felhantering på olika sätt baserat på vilken MVC-åtgärd som väljs.

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

Modelltillståndsfel

Information om hur du hanterar modelltillståndsfel finns i Modellbindning och modellverifiering.

Ytterligare resurser

Av Tom Dykstraoch Steve Smith

Den här artikeln beskriver vanliga metoder för att hantera fel i ASP.NET Core-webbappar. Se Hantera fel i ASP.NET Core-styrenhetsbaserade webb-API:er för webb-API:er.

Visa eller ladda ned exempelkod. (Så här laddar du ner.)

Undantagssida för utvecklare

Undantag för Utvecklare-sidan visar detaljerad information om förfrågningsundantag. Mallarna ASP.NET Core genererar följande kod:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Föregående kod aktiverar undantagssidan för utvecklare när appen körs i Utvecklingsmiljö.

Mallarna placerar UseDeveloperExceptionPage före mellanprogram, så undantag fångas i mellanprogrammet som följer.

Föregående kod aktiverar sidan Undantag för utvecklare endast när appen körs i utvecklingsmiljön. Detaljerad undantagsinformation bör inte visas offentligt när appen körs i produktion. Mer information om hur du konfigurerar miljöer finns i Använda flera miljöer i ASP.NET Core.

Sidan Undantag för utvecklare innehåller följande information om undantaget och begäran:

  • Stackspårning
  • Frågesträngsparametrar om det finns några
  • Eventuella cookies
  • Rubriker

Undantagshanteringssidan

Om du vill konfigurera en anpassad sida för felhantering för produktionsmiljön använder du mellanprogrammet Undantagshantering. Mellanprogrammet:

  • Fångar upp och loggar undantag.
  • Kör begäran på nytt i en alternativ pipeline för den angivna sidan eller kontrollanten. Begäran utförs inte på nytt om svaret redan har påbörjats. Den mallgenererade koden kör om begäran till /Error.

I följande exempel lägger UseExceptionHandler till undantagshanteringsmellanprogram i miljöer som inte är utvecklingsmiljöer:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Appmallen Razor Pages innehåller en felsida (.cshtml) och PageModel -klass (ErrorModel) i mappen Pages. För en MVC-app innehåller projektmallen en metod för felåtgärd och en felvy i Home kontrollanten.

Markera inte felhanteraråtgärdsmetoden med HTTP-metodattribut, till exempel HttpGet. Explicita verb förhindrar att vissa begäranden når metoden. Tillåt anonym åtkomst till metoden om oautentiserade användare ska se felvyn.

Få åtkomst till undantaget

Använd IExceptionHandlerPathFeature för att komma åt undantaget och den ursprungliga sökvägen för begäran på en felhanterarkontrollant eller sida:

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

Varning

inte hantera känslig felinformation till klienter. Att servera fel är en säkerhetsrisk.

Om du vill utlösa föregående sida för undantagshantering anger du miljön till produktioner och framtvingar ett undantag.

Undantagshanteringslambda

Ett alternativ till en anpassad undantagshanterarsida är att ange en lambda för UseExceptionHandler. Med hjälp av en lambda kan du komma åt felet innan svaret returneras.

Här är ett exempel på hur du använder en lambda för undantagshantering:

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

I föregående kod läggs await context.Response.WriteAsync(new string(' ', 512)); till så att Webbläsaren Internet Explorer visar felmeddelandet i stället för ett IE-felmeddelande. Mer information finns i det här GitHub-ärendet.

Varning

inte hantera känslig felinformation från IExceptionHandlerFeature eller IExceptionHandlerPathFeature till klienter. Att leverera fel är en säkerhetsrisk.

Om du vill se resultatet av undantagshanteringen av lambda i exempelappenanvänder du ProdEnvironment- och ErrorHandlerLambda förprocessordirektiven och väljer Utlösa ett undantag på sidan home.

UseStatusCodePages

Som standard tillhandahåller inte en ASP.NET Core-app någon statuskodsida för HTTP-statuskoder, till exempel 404 – Hittades inte. Appen returnerar en statuskod och en tom svarstext. Om du vill ange statuskodsidor använder du mellanprogram för statuskodsidor.

Mellanprogrammet görs tillgängligt av paketet Microsoft.AspNetCore.Diagnostics.

Om du vill aktivera standardhanterare med endast text för vanliga felstatuskoder anropar du UseStatusCodePages i metoden Startup.Configure:

app.UseStatusCodePages();

Anropa UseStatusCodePages innan du begär hantering av mellanprogram (till exempel Static File Middleware och MVC Middleware).

När UseStatusCodePages inte används returnerar navigering till en URL utan en slutpunkt ett webbläsarberoende felmeddelande som anger att slutpunkten inte kan hittas. Du kan till exempel navigera till Home/Privacy2. När UseStatusCodePages anropas returnerar webbläsaren:

Status Code: 404; Not Found

UseStatusCodePages med formatsträng

Om du vill anpassa svarsinnehållstypen och texten använder du överlagringen av UseStatusCodePages som tar en innehållstyp och formatsträng:

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

UseStatusCodePages med lambda

För att ange anpassad felhanterings- och svarsskrivningskod, använd den överlagrade versionen av UseStatusCodePages som tar ett lambda-uttryck.

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

Tilläggsmetoden UseStatusCodePagesWithRedirects:

  • Skickar en 302 – Hittade statuskod till klienten.
  • Omdirigerar klienten till den plats som anges i URL-mallen.
app.UseStatusCodePagesWithRedirects("/StatusCode?code={0}");

URL-mallen kan innehålla en {0}-platshållare för statuskoden, som visas i exemplet. Om URL-mallen börjar med ~ (tilde) ersätts ~ av appens PathBase. Om du pekar på en slutpunkt i appen skapar du en MVC-vy eller Razor sida för slutpunkten. Ett Pages-exempel finns i i exempelappenför .

Den här metoden används ofta när appen:

  • Ska omdirigera klienten till en annan slutpunkt, vanligtvis i fall där en annan app bearbetar felet. För webbappar återspeglar klientens webbläsaradressfält den omdirigerade slutpunkten.
  • Bör inte bevara och returnera den ursprungliga statuskoden med det första omdirigeringssvaret.

UseStatusCodePagesWithReExecute

Tilläggsmetod UseStatusCodePagesWithReExecute:

  • Returnerar den ursprungliga statuskoden till klienten.
  • Genererar svarstexten genom att köra begärandepipelinen igen med hjälp av en alternativ sökväg.
app.UseStatusCodePagesWithReExecute("/StatusCode","?code={0}");

Om du pekar på en slutpunkt i appen skapar du en MVC-vy eller Razor sida för slutpunkten. Kontrollera att UseStatusCodePagesWithReExecute placeras före UseRouting så att begäran kan omdirigeras till statussidan. Ett Razor Pages-exempel finns i Pages/StatusCode.cshtml i demoappen.

Den här metoden används ofta när appen ska:

  • Bearbeta begäran utan att omdirigera till en annan slutpunkt. För webbappar återspeglar klientens webbläsaradressfält den ursprungligen begärda slutpunkten.
  • Bevara och returnera den ursprungliga statuskoden med svaret.

Url- och frågesträngmallarna kan innehålla en platshållare ({0}) för statuskoden. URL-mallen måste börja med ett snedstreck (/). När du använder en platshållare i sökvägen kontrollerar du att slutpunkten (sidan eller kontrollanten) kan bearbeta sökvägssegmentet. Till exempel bör en Razor sida för fel acceptera det valfria sökvägssegmentvärdet med @page-direktivet:

@page "{code?}"

Slutpunkten som bearbetar felet kan hämta den ursprungliga URL:en som genererade felet, enligt följande exempel:

var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
    OriginalURL =
        statusCodeReExecuteFeature.OriginalPathBase
        + statusCodeReExecuteFeature.OriginalPath
        + statusCodeReExecuteFeature.OriginalQueryString;
}

Markera inte felhanteraråtgärdsmetoden med HTTP-metodattribut, till exempel HttpGet. Explicita verb förhindrar att vissa begäranden når metoden. Tillåt anonym åtkomst till metoden om oautentiserade användare ska se felvyn.

Inaktivera statuskodsidor

Om du vill inaktivera statuskodsidor för en MVC-kontrollant eller åtgärdsmetod använder du attributet [SkipStatusCodePages].

Om du vill inaktivera statuskodsidor för specifika begäranden i en Razor Pages-hanteringsmetod eller i en MVC-styrenhet använder du IStatusCodePagesFeature:

var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();

if (statusCodePagesFeature != null)
{
    statusCodePagesFeature.Enabled = false;
}

Kod för undantagshantering

Kod i undantagshanteringssidor kan utlösa undantag. Det är ofta en bra idé att produktionsfelsidor består av rent statiskt innehåll.

Svarshuvuden

När rubrikerna för ett svar har skickats:

  • Appen kan inte ändra svarets statuskod.
  • Undantagssidor eller hanterare kan inte köras. Svaret måste slutföras eller så avbryts anslutningen.

Hantering av serverfel

Förutom logiken för undantagshantering i din app kan HTTP-serverimplementering hantera vissa undantag. Om servern upptäcker ett undantag innan svarshuvuden skickas skickar servern ett 500 – internt serverfel svar utan svarstext. Om servern får ett undantag när svarshuvuden har skickats stänger servern anslutningen. Begäranden som inte hanteras av din app hanteras av servern. Alla undantag som inträffar när servern hanterar begäran hanteras av serverns undantagshantering. Appens anpassade felsidor, undantagshantering av mellanprogram och filter påverkar inte det här beteendet.

Undantagshantering vid start

Endast värdlagret kan hantera undantag som sker under appstarten. Värden kan konfigureras för att registrera startfel och logga detaljerade fel.

Värdlagret kan visa en felsida för ett insamlat startfel endast om felet inträffar efter värdadress/portbindning. Om bindningen misslyckas:

  • Värdlagret loggar ett kritiskt undantag.
  • Dotnet-processen kraschar.
  • Ingen felsida visas när HTTP-servern är Kestrel.

När du kör på IIS (eller Azure App Service) eller IIS Expressreturneras en 502.5 – Processfel av ASP.NET Core-modulen om processen inte kan starta. Mer information finns i Felsöka ASP.NET Core i Azure App Service och IIS.

Databasfel-sida

Database Error Page Middleware samlar in databasrelaterade undantag som kan lösas med hjälp av Entity Framework-migreringar. När dessa undantag inträffar genereras ett HTML-svar med information om möjliga åtgärder för att lösa problemet. Den här sidan bör endast aktiveras i utvecklingsmiljön. Aktivera sidan genom att lägga till kod i Startup.Configure:

if (env.IsDevelopment())
{
    app.UseDatabaseErrorPage();
}

UseDatabaseErrorPage kräver Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet-paketet.

Undantagsfilter

I MVC-appar kan undantagsfilter konfigureras globalt eller per kontrollant eller per åtgärd. I Razor Pages-appar kan de konfigureras globalt eller per sidmodell. Dessa filter hanterar alla ohanterade undantag som inträffar under körningen av en kontrollantåtgärd eller ett annat filter. Mer information finns i filter i ASP.NET Core.

Tips

Undantagsfilter är användbara för att fånga undantag som inträffar inom MVC-funktioner, men de är inte lika flexibla som undantagshanteringsmellanlager. Vi rekommenderar att du använder mellanprogrammet. Använd endast filter där du behöver utföra felhantering på olika sätt baserat på vilken MVC-åtgärd som väljs.

Modelltillståndsfel

Information om hur du hanterar modelltillståndsfel finns i Modellbindning och modellverifiering.

Ytterligare resurser