Zpracování chyb v minimálních aplikacích API

Poznámka:

Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Upozorňující

Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v tématu .NET a .NET Core Zásady podpory. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Důležité

Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

S příspěvky davida Ackera

Tento článek popisuje, jak řešit chyby v minimálních aplikacích API. Informace o zpracování chyb v rozhraních API založených na kontroleru najdete v tématu Zpracování chyb v ASP.NET Core a zpracování chyb ve webových rozhraních API založených na řadiči jádra ASP.NET.

Výjimky

V aplikaci s minimálním rozhraním API existují dva různé integrované centralizované mechanismy pro zpracování neošetřených výjimek:

Tato část odkazuje na následující ukázkovou aplikaci, která demonstruje způsoby zpracování výjimek v minimálním rozhraní API. Při vyžádání koncového bodu /exception dojde k výjimce:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Stránka výjimky pro vývojáře

Na stránce výjimka pro vývojáře se zobrazují podrobné informace o neošetřených výjimkách požadavků. Používá DeveloperExceptionPageMiddleware se k zaznamenání synchronních a asynchronních výjimek z kanálu HTTP a k vygenerování chybových odpovědí. Stránka výjimky vývojáře se spouští v rané fázi kanálu middlewaru, aby bylo možné zachytit neošetřené výjimky vyvolané v middlewaru, které následuje.

ASP.NET aplikace Core ve výchozím nastavení povolí stránku výjimky pro vývojáře, pokud jsou obě:

Aplikace vytvořené pomocí dřívějších šablon, tj. pomocí WebHost.CreateDefaultBuilder, mohou povolit stránku výjimky vývojáře voláním app.UseDeveloperExceptionPage.

Upozorňující

Nepovolujte stránku výjimek vývojáře, pokud aplikace není spuštěná ve vývojovém prostředí. Nesdílejte podrobné informace o výjimce veřejně, když aplikace běží v produkčním prostředí. Další informace o konfiguraci prostředí najdete v tématu Použití více prostředí v ASP.NET Core.

Stránka výjimky pro vývojáře může obsahovat následující informace o výjimce a požadavku:

  • Trasování zásobníku
  • Parametry řetězce dotazu, pokud nějaké
  • Soubory cookie, pokud nějaké
  • Hlavičky
  • Metadata koncového bodu, pokud existuje

Na stránce výjimky pro vývojáře není zaručeno, že poskytnete žádné informace. Protokolování slouží k úplným informacím o chybě.

Následující obrázek ukazuje ukázkovou stránku výjimky vývojáře s animací, která zobrazuje karty a zobrazené informace:

Stránka výjimky vývojáře animované pro zobrazení jednotlivých vybraných karet

V reakci na požadavek s hlavičkou Accept: text/plain vrátí stránka výjimky vývojáře místo HTML prostý text. Příklad:

Status: 500 Internal Server Error
Time: 9.39 msSize: 480 bytes
FormattedRawHeadersRequest
Body
text/plain; charset=utf-8, 480 bytes
System.InvalidOperationException: Sample Exception
   at WebApplicationMinimal.Program.<>c.<Main>b__0_0() in C:\Source\WebApplicationMinimal\Program.cs:line 12
   at lambda_method1(Closure, Object, HttpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

HEADERS
=======
Accept: text/plain
Host: localhost:7267
traceparent: 00-0eab195ea19d07b90a46cd7d6bf2f

Zobrazení stránky výjimky pro vývojáře:

  • Spusťte ukázkovou aplikaci ve vývojovém prostředí.
  • Přejděte na /exception koncový bod.

Obslužná rutina výjimky

V prostředích, která nejsou vývojová, použijte middleware obslužné rutiny výjimky k vytvoření datové části chyby. Konfigurace Exception Handler Middlewarevolání UseExceptionHandler.

Následující kód například změní aplikaci tak, aby odpovídala datové části kompatibilní s dokumentem RFC 7807 pro klienta. Další informace najdete v části Podrobnosti o problému dále v tomto článku.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp 
    => exceptionHandlerApp.Run(async context 
        => await Results.Problem()
                     .ExecuteAsync(context)));

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Odpovědi na chyby klienta a serveru

Zvažte následující minimální aplikaci API.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Koncový /users bod vytvoří json 200 OK reprezentaciUser, kdy id je větší než 0, jinak stavový 400 BAD REQUEST kód bez textu odpovědi. Další informace o vytvoření odpovědi najdete v tématu Vytváření odpovědí v minimálních aplikacích API.

Status Code Pages middleware se nakonfigurovat tak, aby vytvářel společný základní obsah, pokud je prázdný, pro všechny odpovědi klienta HTTP (499-400) nebo serveru ().500 -599 Middleware je nakonfigurován voláním UseStatusCodePages rozšiřující metoda.

Následující příklad například změní aplikaci tak, aby reagovala na datovou část kompatibilní se standardem RFC 7807 pro klienta pro všechny odpovědi klienta a serveru, včetně chyb směrování (například 404 NOT FOUND). Další informace najdete v části Podrobnosti o problému.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseStatusCodePages(async statusCodeContext 
    => await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
                 .ExecuteAsync(statusCodeContext.HttpContext));

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Podrobnosti o problému

Podrobnosti o problému nejsou jediným formátem odpovědi, který popisuje chybu rozhraní HTTP API, ale běžně se používají k hlášení chyb pro rozhraní HTTP API.

Služba podrobností problému implementuje IProblemDetailsService rozhraní, které podporuje vytváření podrobností o problému v ASP.NET Core. Metoda AddProblemDetails(IServiceCollection) rozšíření při IServiceCollection registraci výchozí IProblemDetailsService implementace.

V aplikacích ASP.NET Core generuje následující middleware při zavolání podrobnosti o problému odpovědi AddProblemDetails HTTP, s výjimkou případů, kdy Accept hlavička HTTP požadavku neobsahuje jeden z typů obsahu podporovaných zaregistrovaným IProblemDetailsWriter (výchozí: application/json):

Minimální aplikace API je možné nakonfigurovat tak, aby generovaly odpověď na podrobnosti o problému pro všechny odpovědi na chyby klienta HTTP a serveru, které ještě nemají základní obsah pomocí AddProblemDetails metody rozšíření.

Následující kód nakonfiguruje aplikaci tak, aby vygenerovala podrobnosti o problému:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

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

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Další informace o použití AddProblemDetailsnaleznete v tématu Podrobnosti o problému.

Náhradní služba IProblemDetailsService

V následujícím kódu vrátí chybu, httpContext.Response.WriteAsync("Fallback: An error occurred.") pokud IProblemDetailsService implementace nemůže vygenerovat ProblemDetails:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/exception", () =>
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Předchozí kód:

  • Zapíše chybovou zprávu s náhradním kódem, pokud problemDetailsService není schopen napsat ProblemDetails. Například koncový bod, kde hlavička přijmout požadavek určuje typ média, který DefaulProblemDetailsWriter nepodporuje.
  • Používá middleware obslužné rutiny výjimek.

Následující ukázka je podobná předchozímu s tím rozdílem, že volá Status Code Pages middleware.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseStatusCodePages(statusCodeHandlerApp =>
{
    statusCodeHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/users/{id:int}", (int id) =>
{
    return id <= 0 ? Results.BadRequest() : Results.Ok(new User(id));
});

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Tento článek popisuje, jak řešit chyby v minimálních aplikacích API.

Výjimky

V aplikaci s minimálním rozhraním API existují dva různé integrované centralizované mechanismy pro zpracování neošetřených výjimek:

Tato část se týká následující aplikace s minimálním rozhraním API, která ukazuje způsoby zpracování výjimek. Při vyžádání koncového bodu /exception dojde k výjimce:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });

app.Run();

Stránka výjimky pro vývojáře

Na stránce výjimky pro vývojáře se zobrazují podrobné trasování zásobníku pro chyby serveru. Používá DeveloperExceptionPageMiddleware se k zaznamenání synchronních a asynchronních výjimek z kanálu HTTP a k vygenerování chybových odpovědí.

ASP.NET aplikace Core ve výchozím nastavení povolí stránku výjimky pro vývojáře, pokud jsou obě:

Další informace o konfiguraci middlewaru najdete v tématu Middleware v minimálních aplikacích API.

Při použití předchozí minimální aplikace API, když Developer Exception Page zjistí neošetřenou výjimku, vygeneruje výchozí odpověď ve formátu prostého textu podobnou následujícímu příkladu:

HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
Date: Thu, 27 Oct 2022 18:00:59 GMT
Server: Kestrel
Transfer-Encoding: chunked

    System.InvalidOperationException: Sample Exception
    at Program.<>c.<<Main>$>b__0_1() in ....:line 17
    at lambda_method2(Closure, Object, HttpContext)
    at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
    --- End of stack trace from previous location ---
    at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Connection: keep-alive
Host: localhost:5239
Accept-Encoding: gzip, deflate, br

Upozorňující

Nepovolujte stránku výjimek vývojáře, pokud aplikace není spuštěná ve vývojovém prostředí. Nesdílejte podrobné informace o výjimce veřejně, když aplikace běží v produkčním prostředí. Další informace o konfiguraci prostředí najdete v tématu Použití více prostředí v ASP.NET Core.

Obslužná rutina výjimky

V prostředích, která nejsou vývojová, použijte middleware obslužné rutiny výjimky k vytvoření datové části chyby. Konfigurace Exception Handler Middlewarevolání UseExceptionHandler.

Následující kód například změní aplikaci tak, aby odpovídala datové části kompatibilní s dokumentem RFC 7807 pro klienta. Další informace naleznete v části Podrobnosti o problému.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp 
    => exceptionHandlerApp.Run(async context 
        => await Results.Problem()
                     .ExecuteAsync(context)));

app.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });

app.Run();

Odpovědi na chyby klienta a serveru

Zvažte následující minimální aplikaci API.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.Run();

public record User(int Id);

Koncový /users bod vytvoří json 200 OK reprezentaciUser, kdy id je větší než 0, jinak stavový 400 BAD REQUEST kód bez textu odpovědi. Další informace o vytvoření odpovědi najdete v tématu Vytváření odpovědí v minimálních aplikacích API.

Status Code Pages middleware se nakonfigurovat tak, aby vytvářel společný základní obsah, pokud je prázdný, pro všechny odpovědi klienta HTTP (499-400) nebo serveru ().500 -599 Middleware je nakonfigurován voláním UseStatusCodePages rozšiřující metoda.

Následující příklad například změní aplikaci tak, aby reagovala na datovou část kompatibilní se standardem RFC 7807 pro klienta pro všechny odpovědi klienta a serveru, včetně chyb směrování (například 404 NOT FOUND). Další informace najdete v části Podrobnosti o problému.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseStatusCodePages(async statusCodeContext 
    =>  await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
                 .ExecuteAsync(statusCodeContext.HttpContext));

app.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.Run();

public record User(int Id);

Podrobnosti o problému

Podrobnosti o problému nejsou jediným formátem odpovědi, který popisuje chybu rozhraní HTTP API, ale běžně se používají k hlášení chyb pro rozhraní HTTP API.

Služba podrobností problému implementuje IProblemDetailsService rozhraní, které podporuje vytváření podrobností o problému v ASP.NET Core. Metoda AddProblemDetails(IServiceCollection) rozšíření při IServiceCollection registraci výchozí IProblemDetailsService implementace.

V aplikacích ASP.NET Core generuje následující middleware při zavolání podrobnosti o problému odpovědi AddProblemDetails HTTP, s výjimkou případů, kdy Accept hlavička HTTP požadavku neobsahuje jeden z typů obsahu podporovaných zaregistrovaným IProblemDetailsWriter (výchozí: application/json):

Minimální aplikace API je možné nakonfigurovat tak, aby generovaly odpověď na podrobnosti o problému pro všechny odpovědi na chyby klienta HTTP a serveru, které ještě nemají základní obsah pomocí AddProblemDetails metody rozšíření.

Následující kód nakonfiguruje aplikaci tak, aby vygenerovala podrobnosti o problému:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

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

app.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });

app.Run();

Další informace o použití AddProblemDetailsnaleznete v tématu Podrobnosti o problému.