Delen via


Fouten afhandelen in ASP.NET Core-web-API's op basis van een controller

Note

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikel voor de huidige release.

Warning

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie het .NET- en .NET Core-ondersteuningsbeleid voor meer informatie. Zie de .NET 9-versie van dit artikel voor de huidige release.

Important

Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.

Zie de .NET 9-versie van dit artikel voor de huidige release.

In dit artikel wordt beschreven hoe u fouten kunt afhandelen en foutafhandeling kunt aanpassen in op controller gebaseerde ASP.NET Core-web-API's. Zie Fouten in ASP.NET Core verwerken en fouten verwerken in minimale API's voor informatie over foutafhandeling in minimale API's.

Uitzonderingspagina voor ontwikkelaars

Op de uitzonderingspagina voor ontwikkelaars wordt gedetailleerde informatie weergegeven over niet-verwerkte aanvraag-uitzonderingen. Het maakt gebruik DeveloperExceptionPageMiddleware van het vastleggen van synchrone en asynchrone uitzonderingen van de HTTP-pijplijn en voor het genereren van foutreacties. De ontwikkelaarsexceptiepagina draait vroeg in de middleware-pijplijn, zodat onopgevangen uitzonderingen die in de daaropvolgende middleware worden gegooid, kunnen worden opgevangen.

ASP.NET Core-apps de uitzonderingspagina voor ontwikkelaars standaard inschakelen wanneer beide:

Apps die zijn gemaakt met behulp van eerdere sjablonen, dat wil zeggen door WebHost.CreateDefaultBuilder te gebruiken, kunnen de uitzonderingspagina voor ontwikkelaars inschakelen door app.UseDeveloperExceptionPage aan te roepen.

Warning

Schakel de uitzonderingspagina voor ontwikkelaars alleen in als de app wordt uitgevoerd in de ontwikkelomgeving. Deel geen gedetailleerde uitzonderingsgegevens openbaar wanneer de app in productie wordt uitgevoerd. Zie Meerdere omgevingen gebruiken in ASP.NET Core voor meer informatie over het configureren van omgevingen.

De uitzonderingspagina voor ontwikkelaars kan de volgende informatie bevatten over de uitzondering en de aanvraag:

  • Stack trace
  • Queryreeksparameters, indien van toepassing
  • Cookies, indien van toepassing
  • Headers
  • Eindpuntmetagegevens, indien van toepassing

De uitzonderingspagina voor ontwikkelaars is niet gegarandeerd informatie te verstrekken. Gebruik Logging voor volledige foutinformatie.

In de volgende afbeelding ziet u een voorbeeld van een uitzonderingspagina voor ontwikkelaars met animatie om de tabbladen en de weergegeven informatie weer te geven:

Ontwikkelaar uitzondering pagina geanimeerd om te laten zien welk tabblad is geselecteerd.

Als reactie op een aanvraag met een Accept: text/plain header retourneert de uitzonderingspagina voor ontwikkelaars tekst zonder opmaak in plaats van HTML. For example:

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

Ga als volgende te werk om de uitzonderingspagina voor ontwikkelaars weer te geven:

  • Voeg de volgende controlleractie toe aan een api op basis van een controller. De actie genereert een uitzondering wanneer het eindpunt wordt aangevraagd.

    [HttpGet("Throw")]
    public IActionResult Throw() =>
        throw new Exception("Sample exception.");
    
  • Voer de app uit in de ontwikkelomgeving.

  • Ga naar het eindpunt dat is gedefinieerd door de controlleractie.

Exception handler

In niet-ontwikkelomgevingen gebruikt u Middleware voor uitzonderingsafhandeling om een foutpayload te produceren:

  1. UseExceptionHandler Roep Program.csin aan om de Middleware voor uitzonderingsafhandeling toe te voegen:

    var app = builder.Build();
    
    app.UseHttpsRedirection();
    
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/error");
    }
    
    app.UseAuthorization();
    
    app.MapControllers();
    
    app.Run();
    
  2. Configureer een controlleractie om te reageren op de /error route:

    [Route("/error")]
    public IActionResult HandleError() =>
        Problem();
    

Met de voorgaande HandleError actie wordt een rfC 7807-compatibele nettolading naar de client verzonden.

Warning

Markeer de actiemethode voor de fouthandler niet met HTTP-methodekenmerken, zoals HttpGet. Expliciete werkwoorden voorkomen dat sommige aanvragen de actiemethode bereiken.

Voor web-API's die gebruikmaken van Swagger/OpenAPI, markeert u de actie fouthandler met het kenmerk [ApiExplorerSettings] en stelt u de eigenschap in IgnoreApi op true. Deze kenmerkconfiguratie sluit de actie fouthandler uit van de OpenAPI-specificatie van de app:

[ApiExplorerSettings(IgnoreApi = true)]

Anonieme toegang tot de methode toestaan als niet-geverifieerde gebruikers de fout moeten zien.

Middleware voor uitzonderingsafhandeling kan ook worden gebruikt in de ontwikkelomgeving om een consistente payload-indeling te produceren in alle omgevingen:

  1. Program.csRegistreer omgevingsspecifieke Middleware-exemplaren voor uitzonderingsafhandeling:

    if (app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/error-development");
    }
    else
    {
        app.UseExceptionHandler("/error");
    }
    

    In de voorgaande code wordt de middleware geregistreerd bij:

    • Een route van /error-development in de ontwikkelomgeving.
    • Een route van /error niet-ontwikkelomgevingen.

  2. Controlleracties toevoegen voor zowel de ontwikkelings- als niet-ontwikkelingsroutes:

    [Route("/error-development")]
    public IActionResult HandleErrorDevelopment(
        [FromServices] IHostEnvironment hostEnvironment)
    {
        if (!hostEnvironment.IsDevelopment())
        {
            return NotFound();
        }
    
        var exceptionHandlerFeature =
            HttpContext.Features.Get<IExceptionHandlerFeature>()!;
    
        return Problem(
            detail: exceptionHandlerFeature.Error.StackTrace,
            title: exceptionHandlerFeature.Error.Message);
    }
    
    [Route("/error")]
    public IActionResult HandleError() =>
        Problem();
    

Uitzonderingen gebruiken om het antwoord te wijzigen

De inhoud van het antwoord kan worden gewijzigd van buiten de controller met behulp van een aangepaste uitzondering en een actiefilter:

  1. Maak een bekend uitzonderingstype met de naam HttpResponseException:

    public class HttpResponseException : Exception
    {
        public HttpResponseException(int statusCode, object? value = null) =>
            (StatusCode, Value) = (statusCode, value);
    
        public int StatusCode { get; }
    
        public object? Value { get; }
    }
    
  2. Maak een actiefilter met de naam HttpResponseExceptionFilter:

    public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
    {
        public int Order => int.MaxValue - 10;
    
        public void OnActionExecuting(ActionExecutingContext context) { }
    
        public void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Exception is HttpResponseException httpResponseException)
            {
                context.Result = new ObjectResult(httpResponseException.Value)
                {
                    StatusCode = httpResponseException.StatusCode
                };
    
                context.ExceptionHandled = true;
            }
        }
    }
    

    Het voorgaande filter geeft een Order van de maximumwaarde voor gehele getallen min 10 op. Hierdoor Order kunnen andere filters aan het einde van de pijplijn worden uitgevoerd.

  3. Voeg Program.csin het actiefilter het volgende toe aan de verzameling filters:

    builder.Services.AddControllers(options =>
    {
        options.Filters.Add<HttpResponseExceptionFilter>();
    });
    

Foutreactie bij validatiefout

Voor web-API-controllers reageert MVC met een ValidationProblemDetails antwoordtype wanneer modelvalidatie mislukt. MVC gebruikt de resultaten van het samenstellen van InvalidModelStateResponseFactory de foutreactie voor een validatiefout. In het volgende voorbeeld wordt de standaardfactory vervangen door een implementatie die ook ondersteuning biedt voor het opmaken van antwoorden als XML, in Program.cs:

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
            new BadRequestObjectResult(context.ModelState)
            {
                ContentTypes =
                {
                    // using static System.Net.Mime.MediaTypeNames;
                    Application.Json,
                    Application.Xml
                }
            };
    })
    .AddXmlSerializerFormatters();

Antwoord van clientfout

Er wordt een foutresultaat gedefinieerd als resultaat met een HTTP-statuscode van 400 of hoger. Voor web-API-controllers transformeert MVC een foutresultaat om een ProblemDetails.

Het automatisch maken van een ProblemDetails voor foutcodes is standaard ingeschakeld, maar foutreacties kunnen op een van de volgende manieren worden geconfigureerd:

  1. De service voor probleemdetails gebruiken
  2. Implement ProblemDetailsFactory
  3. Use ApiBehaviorOptions.ClientErrorMapping

Antwoord met standaardprobleemdetails

Het volgende Program.cs bestand is gegenereerd door de webtoepassingssjablonen voor API-controllers:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Houd rekening met de volgende controller, die wordt geretourneerd BadRequest wanneer de invoer ongeldig is:

[Route("api/[controller]/[action]")]
[ApiController]
public class Values2Controller : ControllerBase
{
    // /api/values2/divide/1/2
    [HttpGet("{Numerator}/{Denominator}")]
    public IActionResult Divide(double Numerator, double Denominator)
    {
        if (Denominator == 0)
        {
            return BadRequest();
        }

        return Ok(Numerator / Denominator);
    }

    // /api/values2 /squareroot/4
    [HttpGet("{radicand}")]
    public IActionResult Squareroot(double radicand)
    {
        if (radicand < 0)
        {
            return BadRequest();
        }

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

Er wordt een antwoord voor probleemdetails gegenereerd met de voorgaande code wanneer een van de volgende voorwaarden van toepassing is:

  • Het /api/values2/divide eindpunt wordt aangeroepen met een nul noemer.
  • Het /api/values2/squareroot eindpunt wordt aangeroepen met een radicand kleiner dan nul.

De standaardtekst van de antwoordtekst met probleemdetails heeft de volgende type, titleen status waarden:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "Bad Request",
  "status": 400,
  "traceId": "00-84c1fd4063c38d9f3900d06e56542d48-85d1d4-00"
}

Service voor probleemdetails

ASP.NET Core biedt ondersteuning voor het maken van probleemdetails voor HTTP-API's met behulp van de IProblemDetailsService. Zie de service Probleemdetails voor meer informatie.

Met de volgende code wordt de app geconfigureerd voor het genereren van een antwoord op probleemdetails voor alle HTTP-client- en serverfoutreacties die nog geen hoofdtekstinhoud hebben:

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

Houd rekening met de API-controller uit de vorige sectie, die retourneert BadRequest wanneer de invoer ongeldig is:

[Route("api/[controller]/[action]")]
[ApiController]
public class Values2Controller : ControllerBase
{
    // /api/values2/divide/1/2
    [HttpGet("{Numerator}/{Denominator}")]
    public IActionResult Divide(double Numerator, double Denominator)
    {
        if (Denominator == 0)
        {
            return BadRequest();
        }

        return Ok(Numerator / Denominator);
    }

    // /api/values2 /squareroot/4
    [HttpGet("{radicand}")]
    public IActionResult Squareroot(double radicand)
    {
        if (radicand < 0)
        {
            return BadRequest();
        }

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

Er wordt een antwoord voor probleemdetails gegenereerd met de voorgaande code wanneer een van de volgende voorwaarden van toepassing is:

  • Er wordt een ongeldige invoer opgegeven.
  • De URI heeft geen overeenkomend eindpunt.
  • Er treedt een onverwerkte uitzondering op.

Het automatisch maken van een ProblemDetails voor foutcodes is uitgeschakeld wanneer de SuppressMapClientErrors eigenschap is ingesteld trueop:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressMapClientErrors = true;
    });

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Wanneer een API-controller wordt geretourneerd BadRequest, wordt met behulp van de voorgaande code een HTTP 400-antwoordstatus geretourneerd zonder hoofdtekst van het antwoord. SuppressMapClientErrors voorkomt dat er een ProblemDetails antwoord wordt gemaakt, zelfs wanneer een API Controller-eindpunt wordt aangeroepen WriteAsync . WriteAsync wordt verderop in dit artikel uitgelegd.

In de volgende sectie ziet u hoe u de hoofdtekst van de antwoordtekst van de probleemdetails kunt aanpassen, om CustomizeProblemDetailseen nuttiger antwoord te retourneren. Zie Details van het probleem aanpassen voor meer aanpassingsopties.

Probleemdetails aanpassen met CustomizeProblemDetails

De volgende code gebruikt ProblemDetailsOptions om in te stellen CustomizeProblemDetails:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddProblemDetails(options =>
        options.CustomizeProblemDetails = (context) =>
        {

            var mathErrorFeature = context.HttpContext.Features
                                                       .Get<MathErrorFeature>();
            if (mathErrorFeature is not null)
            {
                (string Detail, string Type) details = mathErrorFeature.MathError switch
                {
                    MathErrorType.DivisionByZeroError =>
                    ("Divison by zero is not defined.",
                                          "https://wikipedia.org/wiki/Division_by_zero"),
                    _ => ("Negative or complex numbers are not valid input.",
                                          "https://wikipedia.org/wiki/Square_root")
                };

                context.ProblemDetails.Type = details.Type;
                context.ProblemDetails.Title = "Bad Input";
                context.ProblemDetails.Detail = details.Detail;
            }
        }
    );

var app = builder.Build();

app.UseHttpsRedirection();

app.UseStatusCodePages();

app.UseAuthorization();

app.MapControllers();

app.Run();

De bijgewerkte API-controller:

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

}

De volgende code bevat de MathErrorFeature en MathErrorType, die worden gebruikt met het voorgaande voorbeeld:

// Custom Http Request Feature
class MathErrorFeature
{
    public MathErrorType MathError { get; set; }
}

// Custom math errors
enum MathErrorType
{
    DivisionByZeroError,
    NegativeRadicandError
}

Er wordt een antwoord voor probleemdetails gegenereerd met de voorgaande code wanneer een van de volgende voorwaarden van toepassing is:

  • Het /divide eindpunt wordt aangeroepen met een nul noemer.
  • Het /squareroot eindpunt wordt aangeroepen met een radicand kleiner dan nul.
  • De URI heeft geen overeenkomend eindpunt.

De antwoordtekst van de probleemdetails bevat het volgende wanneer een squareroot van beide eindpunten wordt aangeroepen met een radicand kleiner dan nul:

{
  "type": "https://en.wikipedia.org/wiki/Square_root",
  "title": "Bad Input",
  "status": 400,
  "detail": "Negative or complex numbers are not allowed."
}

Voorbeeldcode weergeven of downloaden

ProblemDetailsFactory implementeren

MVC gebruikt Microsoft.AspNetCore.Mvc.Infrastructure.ProblemDetailsFactory om alle exemplaren van ProblemDetails en ValidationProblemDetails. Deze fabriek wordt gebruikt voor:

Registreer een aangepaste implementatie van ProblemDetailsFactory :Program.cs

builder.Services.AddControllers();
builder.Services.AddTransient<ProblemDetailsFactory, SampleProblemDetailsFactory>();

Gebruik ApiBehaviorOptions.ClientErrorMapping

Gebruik de ClientErrorMapping eigenschap om de inhoud van het ProblemDetails antwoord te configureren. Met de volgende code wordt Program.cs bijvoorbeeld de Link eigenschap bijgewerkt voor 404-antwoorden:

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

Additional resources

In dit artikel wordt beschreven hoe u fouten kunt afhandelen en foutafhandeling kunt aanpassen met ASP.NET Core-web-API's.

Uitzonderingspagina voor ontwikkelaars

Op de uitzonderingspagina voor ontwikkelaars worden gedetailleerde stacktraceringen weergegeven voor serverfouten. Het maakt gebruik DeveloperExceptionPageMiddleware van het vastleggen van synchrone en asynchrone uitzonderingen van de HTTP-pijplijn en voor het genereren van foutreacties. Denk bijvoorbeeld aan de volgende controlleractie, waarmee een uitzondering wordt gegenereerd:

[HttpGet("Throw")]
public IActionResult Throw() =>
    throw new Exception("Sample exception.");

Wanneer de uitzonderingspagina voor ontwikkelaars een niet-verwerkte uitzondering detecteert, wordt er een standaardantwoord zonder opmaak gegenereerd dat vergelijkbaar is met het volgende voorbeeld:

HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked

System.Exception: Sample exception.
   at HandleErrorsSample.Controllers.ErrorsController.Get() in ...
   at lambda_method1(Closure , Object , Object[] )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()

...

Als de client een HTML-indeling aanvraagt, genereert de uitzonderingspagina voor ontwikkelaars een antwoord dat vergelijkbaar is met het volgende voorbeeld:

HTTP/1.1 500 Internal Server Error
Content-Type: text/html; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <title>Internal Server Error</title>
        <style>
            body {
    font-family: 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;
    font-size: .813em;
    color: #222;
    background-color: #fff;
}

h1 {
    color: #44525e;
    margin: 15px 0 15px 0;
}

...

Als u een HTML-opgemaakt antwoord wilt aanvragen, stelt u de Accept HTTP-aanvraagheader in op text/html.

Warning

Schakel de uitzonderingspagina voor ontwikkelaars alleen in als de app wordt uitgevoerd in de ontwikkelomgeving. Deel geen gedetailleerde uitzonderingsgegevens openbaar wanneer de app in productie wordt uitgevoerd. Zie Meerdere omgevingen gebruiken in ASP.NET Core voor meer informatie over het configureren van omgevingen.

Exception handler

In niet-ontwikkelomgevingen gebruikt u Middleware voor uitzonderingsafhandeling om een foutpayload te produceren:

  1. UseExceptionHandler Roep Program.csin aan om de Middleware voor uitzonderingsafhandeling toe te voegen:

    var app = builder.Build();
    
    app.UseHttpsRedirection();
    
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/error");
    }
    
    app.UseAuthorization();
    
    app.MapControllers();
    
    app.Run();
    
  2. Configureer een controlleractie om te reageren op de /error route:

    [Route("/error")]
    public IActionResult HandleError() =>
        Problem();
    

Met de voorgaande HandleError actie wordt een rfC 7807-compatibele nettolading naar de client verzonden.

Warning

Markeer de actiemethode voor de fouthandler niet met HTTP-methodekenmerken, zoals HttpGet. Expliciete werkwoorden voorkomen dat sommige aanvragen de actiemethode bereiken.

Voor web-API's die gebruikmaken van Swagger/OpenAPI, markeert u de actie fouthandler met het kenmerk [ApiExplorerSettings] en stelt u de eigenschap in IgnoreApi op true. Deze kenmerkconfiguratie sluit de actie fouthandler uit van de OpenAPI-specificatie van de app:

[ApiExplorerSettings(IgnoreApi = true)]

Anonieme toegang tot de methode toestaan als niet-geverifieerde gebruikers de fout moeten zien.

Middleware voor uitzonderingsafhandeling kan ook worden gebruikt in de ontwikkelomgeving om een consistente payload-indeling te produceren in alle omgevingen:

  1. Program.csRegistreer omgevingsspecifieke Middleware-exemplaren voor uitzonderingsafhandeling:

    if (app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/error-development");
    }
    else
    {
        app.UseExceptionHandler("/error");
    }
    

    In de voorgaande code wordt de middleware geregistreerd bij:

    • Een route van /error-development in de ontwikkelomgeving.
    • Een route van /error niet-ontwikkelomgevingen.

  2. Controlleracties toevoegen voor zowel de ontwikkelings- als niet-ontwikkelingsroutes:

    [Route("/error-development")]
    public IActionResult HandleErrorDevelopment(
        [FromServices] IHostEnvironment hostEnvironment)
    {
        if (!hostEnvironment.IsDevelopment())
        {
            return NotFound();
        }
    
        var exceptionHandlerFeature =
            HttpContext.Features.Get<IExceptionHandlerFeature>()!;
    
        return Problem(
            detail: exceptionHandlerFeature.Error.StackTrace,
            title: exceptionHandlerFeature.Error.Message);
    }
    
    [Route("/error")]
    public IActionResult HandleError() =>
        Problem();
    

Uitzonderingen gebruiken om het antwoord te wijzigen

De inhoud van het antwoord kan worden gewijzigd van buiten de controller met behulp van een aangepaste uitzondering en een actiefilter:

  1. Maak een bekend uitzonderingstype met de naam HttpResponseException:

    public class HttpResponseException : Exception
    {
        public HttpResponseException(int statusCode, object? value = null) =>
            (StatusCode, Value) = (statusCode, value);
    
        public int StatusCode { get; }
    
        public object? Value { get; }
    }
    
  2. Maak een actiefilter met de naam HttpResponseExceptionFilter:

    public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
    {
        public int Order => int.MaxValue - 10;
    
        public void OnActionExecuting(ActionExecutingContext context) { }
    
        public void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Exception is HttpResponseException httpResponseException)
            {
                context.Result = new ObjectResult(httpResponseException.Value)
                {
                    StatusCode = httpResponseException.StatusCode
                };
    
                context.ExceptionHandled = true;
            }
        }
    }
    

    Het voorgaande filter geeft een Order van de maximumwaarde voor gehele getallen min 10 op. Hierdoor Order kunnen andere filters aan het einde van de pijplijn worden uitgevoerd.

  3. Voeg Program.csin het actiefilter het volgende toe aan de verzameling filters:

    builder.Services.AddControllers(options =>
    {
        options.Filters.Add<HttpResponseExceptionFilter>();
    });
    

Foutreactie bij validatiefout

Voor web-API-controllers reageert MVC met een ValidationProblemDetails antwoordtype wanneer modelvalidatie mislukt. MVC gebruikt de resultaten van het samenstellen van InvalidModelStateResponseFactory de foutreactie voor een validatiefout. In het volgende voorbeeld wordt de standaardfactory vervangen door een implementatie die ook ondersteuning biedt voor het opmaken van antwoorden als XML, in Program.cs:

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
            new BadRequestObjectResult(context.ModelState)
            {
                ContentTypes =
                {
                    // using static System.Net.Mime.MediaTypeNames;
                    Application.Json,
                    Application.Xml
                }
            };
    })
    .AddXmlSerializerFormatters();

Antwoord van clientfout

Er wordt een foutresultaat gedefinieerd als resultaat met een HTTP-statuscode van 400 of hoger. Voor web-API-controllers transformeert MVC een foutresultaat om een ProblemDetails.

De foutreactie kan op een van de volgende manieren worden geconfigureerd:

  1. Implement ProblemDetailsFactory
  2. Use ApiBehaviorOptions.ClientErrorMapping

ProblemDetailsFactory implementeren

MVC gebruikt Microsoft.AspNetCore.Mvc.Infrastructure.ProblemDetailsFactory om alle exemplaren van ProblemDetails en ValidationProblemDetails. Deze fabriek wordt gebruikt voor:

Registreer een aangepaste implementatie van ProblemDetailsFactory :Program.cs

builder.Services.AddControllers();
builder.Services.AddTransient<ProblemDetailsFactory, SampleProblemDetailsFactory>();

Gebruik ApiBehaviorOptions.ClientErrorMapping

Gebruik de ClientErrorMapping eigenschap om de inhoud van het ProblemDetails antwoord te configureren. Met de volgende code wordt Program.cs bijvoorbeeld de Link eigenschap bijgewerkt voor 404-antwoorden:

builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
    });

Aangepaste middleware voor het afhandelen van uitzonderingen

De standaardinstellingen in de uitzondering die middleware verwerken, werken goed voor de meeste apps. Voor apps waarvoor speciale afhandeling van uitzonderingen is vereist, kunt u overwegen om de middleware voor het verwerken van uitzonderingen aan te passen.

Een ProblemDetails-payload genereren voor uitzonderingen

ASP.NET Core produceert geen gestandaardiseerde foutpayload wanneer er een onverwerkte uitzondering optreedt. Voor scenario's waarin het wenselijk is om een gestandaardiseerde ProblemDetails-reactie op de client te retourneren, kan de MiddleWare ProblemDetails worden gebruikt om uitzonderingen en 404 antwoorden toe te wijzen aan een payload van ProblemDetails . De middleware voor het verwerken van uitzonderingen kan ook worden gebruikt om een ProblemDetails nettolading te retourneren voor niet-verwerkte uitzonderingen.

Additional resources

In dit artikel wordt beschreven hoe u foutafhandeling kunt afhandelen en aanpassen met ASP.NET Core-web-API's.

Voorbeeldcode weergeven of downloaden (downloaden)

Uitzonderingspagina voor ontwikkelaars

De uitzonderingspagina voor ontwikkelaars is een handig hulpprogramma om gedetailleerde stacktraceringen voor serverfouten op te halen. Het maakt gebruik DeveloperExceptionPageMiddleware van het vastleggen van synchrone en asynchrone uitzonderingen van de HTTP-pijplijn en voor het genereren van foutreacties. Bekijk ter illustratie de volgende controlleractie:

[HttpGet("{city}")]
public WeatherForecast Get(string city)
{
    if (!string.Equals(city?.TrimEnd(), "Redmond", StringComparison.OrdinalIgnoreCase))
    {
        throw new ArgumentException(
            $"We don't offer a weather forecast for {city}.", nameof(city));
    }
    
    return GetWeather().First();
}

Voer de volgende curl opdracht uit om de voorgaande actie te testen:

curl -i https://localhost:5001/weatherforecast/chicago

Op de uitzonderingspagina voor ontwikkelaars wordt een antwoord zonder opmaak weergegeven als de client geen UITVOER met HTML-indeling aanvraagt. De volgende uitvoer wordt weergegeven:

HTTP/1.1 500 Internal Server Error
Transfer-Encoding: chunked
Content-Type: text/plain
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Fri, 27 Sep 2019 16:13:16 GMT

System.ArgumentException: We don't offer a weather forecast for chicago. (Parameter 'city')
   at WebApiSample.Controllers.WeatherForecastController.Get(String city) in C:\working_folder\aspnet\AspNetCore.Docs\aspnetcore\web-api\handle-errors\samples\3.x\Controllers\WeatherForecastController.cs:line 34
   at lambda_method(Closure , Object , Object[] )
   at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

HEADERS
=======
Accept: */*
Host: localhost:44312
User-Agent: curl/7.55.1

Als u in plaats daarvan een html-opgemaakt antwoord wilt weergeven, stelt u de Accept HTTP-aanvraagheader in op het text/html mediatype. For example:

curl -i -H "Accept: text/html" https://localhost:5001/weatherforecast/chicago

Bekijk het volgende fragment uit het HTTP-antwoord:

HTTP/1.1 500 Internal Server Error
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Fri, 27 Sep 2019 16:55:37 GMT

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <title>Internal Server Error</title>
        <style>
            body {
    font-family: 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;
    font-size: .813em;
    color: #222;
    background-color: #fff;
}

Het HTML-opgemaakte antwoord wordt nuttig bij het testen via hulpprogramma's zoals curl.

Warning

Schakel de uitzonderingspagina voor ontwikkelaars alleen in wanneer de app wordt uitgevoerd in de ontwikkelomgeving. Deel geen gedetailleerde uitzonderingsgegevens openbaar wanneer de app in productie wordt uitgevoerd. Zie Meerdere omgevingen gebruiken in ASP.NET Core voor meer informatie over het configureren van omgevingen.

Markeer de actiemethode voor de fouthandler niet met HTTP-methodekenmerken, zoals HttpGet. Expliciete werkwoorden voorkomen dat sommige aanvragen de actiemethode bereiken. Anonieme toegang tot de methode toestaan als niet-geverifieerde gebruikers de fout moeten zien.

Exception handler

In niet-ontwikkelomgevingen kan Middleware voor uitzonderingsafhandeling worden gebruikt om een foutnlading te produceren:

  1. UseExceptionHandler Roep in Startup.Configureaan om de middleware te gebruiken:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/error");
        }
    
        app.UseHttpsRedirection();
        app.UseRouting();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
    
  2. Configureer een controlleractie om te reageren op de /error route:

    [ApiController]
    public class ErrorController : ControllerBase
    {
        [Route("/error")]
        public IActionResult Error() => Problem();
    }
    

Met de voorgaande Error actie wordt een rfC 7807-compatibele nettolading naar de client verzonden.

Middleware voor het verwerken van uitzonderingen kan ook gedetailleerdere inhoudsonderhandelde uitvoer bieden in de lokale ontwikkelomgeving. Gebruik de volgende stappen om een consistente payload-indeling te maken in ontwikkel- en productieomgevingen:

  1. Startup.ConfigureRegistreer omgevingsspecifieke Middleware-exemplaren voor uitzonderingsafhandeling:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseExceptionHandler("/error-local-development");
        }
        else
        {
            app.UseExceptionHandler("/error");
        }
    }
    

    In de voorgaande code wordt de middleware geregistreerd bij:

    • Een route van /error-local-development in de ontwikkelomgeving.
    • Een route van /error omgevingen die geen ontwikkeling zijn.

  2. Kenmerkroutering toepassen op controlleracties:

    [ApiController]
    public class ErrorController : ControllerBase
    {
        [Route("/error-local-development")]
        public IActionResult ErrorLocalDevelopment(
            [FromServices] IWebHostEnvironment webHostEnvironment)
        {
            if (webHostEnvironment.EnvironmentName != "Development")
            {
                throw new InvalidOperationException(
                    "This shouldn't be invoked in non-development environments.");
            }
    
            var context = HttpContext.Features.Get<IExceptionHandlerFeature>();
    
            return Problem(
                detail: context.Error.StackTrace,
                title: context.Error.Message);
        }
    
        [Route("/error")]
        public IActionResult Error() => Problem();
    }
    

    De voorgaande code roept ControllerBase.Problem aan om een ProblemDetails antwoord te maken.

Uitzonderingen gebruiken om het antwoord te wijzigen

De inhoud van het antwoord kan worden gewijzigd van buiten de controller. In ASP.NET web-API van 4.x is dit een manier om dit te doen.HttpResponseException ASP.NET Core bevat geen equivalent type. Ondersteuning voor HttpResponseException kan worden toegevoegd met de volgende stappen:

  1. Maak een bekend uitzonderingstype met de naam HttpResponseException:

    public class HttpResponseException : Exception
    {
        public int Status { get; set; } = 500;
    
        public object Value { get; set; }
    }
    
  2. Maak een actiefilter met de naam HttpResponseExceptionFilter:

    public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
    {
        public int Order { get; } = int.MaxValue - 10;
    
        public void OnActionExecuting(ActionExecutingContext context) { }
    
        public void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Exception is HttpResponseException exception)
            {
                context.Result = new ObjectResult(exception.Value)
                {
                    StatusCode = exception.Status,
                };
                context.ExceptionHandled = true;
            }
        }
    }
    

    Het voorgaande filter geeft een Order van de maximumwaarde voor gehele getallen min 10 op. Hierdoor Order kunnen andere filters aan het einde van de pijplijn worden uitgevoerd.

  3. Voeg Startup.ConfigureServicesin het actiefilter het volgende toe aan de verzameling filters:

    services.AddControllers(options =>
        options.Filters.Add(new HttpResponseExceptionFilter()));
    

Foutreactie bij validatiefout

Voor web-API-controllers reageert MVC met een ValidationProblemDetails antwoordtype wanneer modelvalidatie mislukt. MVC gebruikt de resultaten van het samenstellen van InvalidModelStateResponseFactory de foutreactie voor een validatiefout. In het volgende voorbeeld wordt de fabriek gebruikt om het standaardantwoordtype te SerializableError wijzigen in Startup.ConfigureServices:

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
        {
            var result = new BadRequestObjectResult(context.ModelState);

            // TODO: add `using System.Net.Mime;` to resolve MediaTypeNames
            result.ContentTypes.Add(MediaTypeNames.Application.Json);
            result.ContentTypes.Add(MediaTypeNames.Application.Xml);

            return result;
        };
    });

Antwoord van clientfout

Er wordt een foutresultaat gedefinieerd als resultaat met een HTTP-statuscode van 400 of hoger. Voor web-API-controllers transformeert MVC een foutresultaat naar een resultaat met ProblemDetails.

De foutreactie kan op een van de volgende manieren worden geconfigureerd:

  1. Implement ProblemDetailsFactory
  2. Use ApiBehaviorOptions.ClientErrorMapping

ProblemDetailsFactory implementeren

MVC gebruikt Microsoft.AspNetCore.Mvc.Infrastructure.ProblemDetailsFactory om alle exemplaren van ProblemDetails en ValidationProblemDetails. Deze fabriek wordt gebruikt voor:

Registreer een aangepaste implementatie van ProblemDetailsFactory :Startup.ConfigureServices

public void ConfigureServices(IServiceCollection serviceCollection)
{
    services.AddControllers();
    services.AddTransient<ProblemDetailsFactory, CustomProblemDetailsFactory>();
}

Use ApiBehaviorOptions.ClientErrorMapping

Gebruik de ClientErrorMapping eigenschap om de inhoud van het ProblemDetails antwoord te configureren. Met de volgende code wordt Startup.ConfigureServices bijvoorbeeld de type eigenschap bijgewerkt voor 404-antwoorden:

services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
        options.ClientErrorMapping[StatusCodes.Status404NotFound].Link =
            "https://httpstatuses.com/404";
        options.DisableImplicitFromServicesParameters = true;
    });

Aangepaste middleware voor het afhandelen van uitzonderingen

De standaardinstellingen in de uitzondering die middleware verwerken, werken goed voor de meeste apps. Voor apps waarvoor speciale afhandeling van uitzonderingen is vereist, kunt u overwegen om de middleware voor het verwerken van uitzonderingen aan te passen.

Een ProblemDetails-nettolading voor uitzonderingen maken

ASP.NET Core produceert geen gestandaardiseerde foutpayload wanneer er een onverwerkte uitzondering optreedt. Voor scenario's waarin het wenselijk is om een gestandaardiseerde ProblemDetails-reactie op de client te retourneren, kan de MiddleWare ProblemDetails worden gebruikt om uitzonderingen en 404 antwoorden toe te wijzen aan een payload van ProblemDetails . De middleware voor het verwerken van uitzonderingen kan ook worden gebruikt om een ProblemDetails nettolading te retourneren voor niet-verwerkte uitzonderingen.