Como tratar erros em aplicativos de API mínima
Observação
Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Aviso
Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, confira .NET e a Política de Suporte do .NET Core. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Importante
Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.
Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Com contribuições de David Acker
Este artigo descreve como tratar erros em aplicativos de API mínima. Para obter informações sobre o tratamento de erros em APIs baseadas em controlador, consulte Manipular erros no ASP.NET Core e Manipular erros em APIs Web baseadas em controlador ASP.NET Core.
Exceções
Em um aplicativo de API mínima, há dois mecanismos centralizados internos diferentes para lidar com exceções sem tratamento:
- Middleware da Página de exceção do desenvolvedor (para uso apenas no ambiente de desenvolvimento).
- Middleware do manipulador de exceção
Esta seção se refere ao aplicativo de amostra a seguir para demonstrar formas de tratar exceções em uma API Mínima. Ele gera uma exceção quando o ponto de extremidade /exception
é solicitado:
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();
Página de exceção do desenvolvedor
A Página de exceção do desenvolvedor exibe informações detalhadas sobre as exceções de solicitação não tratadas. Ele usa DeveloperExceptionPageMiddleware para capturar exceções síncronas e assíncronas do pipeline HTTP e para gerar respostas de erro. A página de exceção do desenvolvedor é executada no início do pipeline do middleware, para que ele possa capturar exceções sem tratamento geradas no middleware a seguir.
Os aplicativos ASP.NET Core habilitam a página de exceção do desenvolvedor por padrão quando ambos:
- Em execução no Ambiente de desenvolvimento.
- O aplicativo foi criado com os modelos atuais, ou seja, usando WebApplication.CreateBuilder.
Os aplicativos criados usando modelos anteriores, ou seja, usando WebHost.CreateDefaultBuilder, podem ativar a página de exceção do desenvolvedor chamando app.UseDeveloperExceptionPage
.
Aviso
Não habilite a Página de exceção do desenvolvedor a menos que o aplicativo esteja em execução no Ambiente de desenvolvimento. Não compartilhe informações de exceção detalhadas publicamente quando o aplicativo é executado em produção. Para obter mais informações sobre como configurar ambientes, confira Use vários ambientes no ASP.NET Core.
A Página de Exceção do Desenvolvedor pode incluir as seguintes informações sobre a exceção e a solicitação:
- Rastreamento de pilha
- Parâmetros de cadeia de caracteres de consulta, se houver
- Cookies, se houver algum
- Cabeçalhos
- Metadados de ponto de extremidade, se houver
Não existe garantia de que a Página de Exceção do Desenvolvedor fornecerá alguma informação. Use Registro em log para obter informações de erro completas.
A imagem a seguir mostra uma página de exceção do desenvolvedor de exemplo com animação para mostrar as guias e as informações exibidas:
Em resposta a uma solicitação com um cabeçalho Accept: text/plain
, a Página de Exceção do Desenvolvedor retorna texto sem formatação em vez de HTML. Por exemplo:
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
Para ver a página de exceção do desenvolvedor:
- Execute o aplicativo de exemplo no Ambiente de desenvolvimento.
- Vá para o ponto de extremidade
/exception
.
Manipulador de exceção
Em ambientes de não desenvolvimento, use o Middleware do manipulador de exceções para produzir um conteúdo de erro. Para configurar o Exception Handler Middleware
, chame UseExceptionHandler.
Por exemplo, o código a seguir altera o aplicativo para responder com um conteúdo compatível com RFC 7807 para o cliente. Para obter mais informações, consulte a seção Detalhes do Problema mais adiante neste artigo.
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();
Respostas de erro de cliente e servidor
Cogite o aplicativo de API mínima a seguir.
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);
O ponto de extremidade /users
produz 200 OK
com uma representação json
do User
quando id
for maior que 0
, caso contrário, produzirá um código de status 400 BAD REQUEST
sem um corpo de resposta. Para obter mais informações sobre como criar uma resposta, confira Criar respostas em aplicativos de API mínimo.
O Status Code Pages middleware
pode ser configurado para produzir um conteúdo de corpo comum, quando vazio, para todas as respostas de cliente HTTP (400
-499
) ou servidor (500
-599
). O middleware é configurado chamando o método de extensão UseStatusCodePages.
O exemplo a seguir altera o aplicativo para responder com uma carga compatível com RFC 7807 para o cliente para todas as respostas de cliente e servidor, incluindo erros de roteamento (por exemplo, 404 NOT FOUND
). Para obter mais informações, confira a seção Detalhes do problema.
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);
Detalhes do problema
Os Detalhes do problema não são o único formato de resposta a descrever um erro de API HTTP; no entanto, eles geralmente são usados para relatar erros para APIs HTTP.
O serviço de detalhes do problema implementa a interface IProblemDetailsService, que dá suporte à criação de detalhes do problema no ASP.NET Core. O método de extensão AddProblemDetails(IServiceCollection) em IServiceCollection regista a implementação IProblemDetailsService
padrão.
Em aplicativos ASP.NET Core, o middleware abaixo gera respostas HTTP de detalhes do problema quando AddProblemDetails
é chamado, exceto quando o cabeçalho HTTP da solicitação Accept
não inclui um dos tipos de conteúdo com suporte pelo IProblemDetailsWriter registrado (padrão: application/json
):
- ExceptionHandlerMiddleware: gera uma resposta de detalhes do problema quando um manipulador personalizado não é definido.
- StatusCodePagesMiddleware: gera uma resposta de detalhes do problema por padrão.
- DeveloperExceptionPageMiddleware: gera uma resposta de detalhes do problema no desenvolvimento quando o cabeçalho HTTP da solicitação
Accept
não incluitext/html
.
Aplicativos de API mínima podem ser configurados para gerar uma resposta de detalhes do problema para todas as respostas de erro de cliente e servidor HTTP que ainda não tenham conteúdo de corpo usando o método de extensão AddProblemDetails
.
O código a seguir configura o aplicativo para gerar detalhes do problema:
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);
Para obter mais informações sobre como usar AddProblemDetails
, confira Detalhes do problema
Fallback de IProblemDetailsService
No código a seguir, httpContext.Response.WriteAsync("Fallback: An error occurred.")
retornará um erro se a implementação IProblemDetailsService não conseguir gerar um 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();
O código anterior:
- Grava uma mensagem de erro com o código de fallback se
problemDetailsService
não conseguir gravar umProblemDetails
. Por exemplo, um ponto de extremidade em que o cabeçalho de solicitação Accept especifica um tipo de mídia com a qual oDefaulProblemDetailsWriter
não é compatível. - Usa o Middleware do manipulador de exceção.
O exemplo a seguir é semelhante ao anterior, exceto que ele chama o 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);
Este artigo descreve como tratar erros em aplicativos de API mínima.
Exceções
Em um aplicativo de API mínima, há dois mecanismos centralizados internos diferentes para lidar com exceções sem tratamento:
- Middleware da Página de exceção do desenvolvedor (para uso apenas no ambiente de desenvolvimento).
- Middleware do manipulador de exceção
Esta seção se refere ao aplicativo de API mínima a seguir para demonstrar formas de tratar exceções. Ele gera uma exceção quando o ponto de extremidade /exception
é solicitado:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/exception", ()
=> { throw new InvalidOperationException("Sample Exception"); });
app.Run();
Página de exceção do desenvolvedor
A Página de exceção do desenvolvedor mostra rastreamentos de pilha detalhados para erros de servidor. Ele usa DeveloperExceptionPageMiddleware para capturar exceções síncronas e assíncronas do pipeline HTTP e para gerar respostas de erro.
Os aplicativos ASP.NET Core habilitam a página de exceção do desenvolvedor por padrão quando ocorrerem estes dois pontos:
- Estiverem em execução no Ambiente de desenvolvimento.
- O aplicativo estiver usando WebApplication.CreateBuilder.
Para obter mais informações sobre como configurar o middleware, confira Middleware em aplicativos de API mínima.
Ao usar o aplicativo de API mínima anterior, quando a Developer Exception Page
detectar uma exceção sem tratamento, será gerada uma resposta de texto sem formatação padrão semelhante ao exemplo a seguir:
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
Aviso
Não habilite a Página de exceção do desenvolvedor a menos que o aplicativo esteja em execução no Ambiente de desenvolvimento. Não compartilhe informações de exceção detalhadas publicamente quando o aplicativo é executado em produção. Para obter mais informações sobre como configurar ambientes, confira Use vários ambientes no ASP.NET Core.
Manipulador de exceção
Em ambientes de não desenvolvimento, use o Middleware do manipulador de exceções para produzir um conteúdo de erro. Para configurar o Exception Handler Middleware
, chame UseExceptionHandler.
Por exemplo, o código a seguir altera o aplicativo para responder com um conteúdo compatível com RFC 7807 para o cliente. Para obter mais informações, confira Detalhes do problema.
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();
Respostas de erro de cliente e servidor
Cogite o aplicativo de API mínima a seguir.
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);
O ponto de extremidade /users
produz 200 OK
com uma representação json
do User
quando id
for maior que 0
, caso contrário, produzirá um código de status 400 BAD REQUEST
sem um corpo de resposta. Para obter mais informações sobre como criar uma resposta, confira Criar respostas em aplicativos de API mínimo.
O Status Code Pages middleware
pode ser configurado para produzir um conteúdo de corpo comum, quando vazio, para todas as respostas de cliente HTTP (400
-499
) ou servidor (500
-599
). O middleware é configurado chamando o método de extensão UseStatusCodePages.
O exemplo a seguir altera o aplicativo para responder com uma carga compatível com RFC 7807 para o cliente para todas as respostas de cliente e servidor, incluindo erros de roteamento (por exemplo, 404 NOT FOUND
). Para obter mais informações, confira a seção Detalhes do problema.
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);
Detalhes do problema
Os Detalhes do problema não são o único formato de resposta a descrever um erro de API HTTP; no entanto, eles geralmente são usados para relatar erros para APIs HTTP.
O serviço de detalhes do problema implementa a interface IProblemDetailsService, que dá suporte à criação de detalhes do problema no ASP.NET Core. O método de extensão AddProblemDetails(IServiceCollection) em IServiceCollection regista a implementação IProblemDetailsService
padrão.
Em aplicativos ASP.NET Core, o middleware abaixo gera respostas HTTP de detalhes do problema quando AddProblemDetails
é chamado, exceto quando o cabeçalho HTTP da solicitação Accept
não inclui um dos tipos de conteúdo com suporte pelo IProblemDetailsWriter registrado (padrão: application/json
):
- ExceptionHandlerMiddleware: gera uma resposta de detalhes do problema quando um manipulador personalizado não é definido.
- StatusCodePagesMiddleware: gera uma resposta de detalhes do problema por padrão.
- DeveloperExceptionPageMiddleware: gera uma resposta de detalhes do problema no desenvolvimento quando o cabeçalho HTTP da solicitação
Accept
não incluitext/html
.
Aplicativos de API mínima podem ser configurados para gerar uma resposta de detalhes do problema para todas as respostas de erro de cliente e servidor HTTP que ainda não tenham um conteúdo de corpo usando o método de extensão AddProblemDetails
.
O código a seguir configura o aplicativo para gerar detalhes do problema:
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();
Para obter mais informações sobre como usar AddProblemDetails
, confira Detalhes do problema