Compartilhar via


Manipular erros em APIs de ASP.NET Core

Observação

Esta não é a versão mais recente deste artigo. Para ver a versão atual, consulte a versão .NET 10 deste artigo.

Aviso

Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, consulte o .NET e .NET Core Support Policy. Para ver a versão atual, consulte a versão .NET 10 deste artigo.

  • APIs mínimas
  • Controladores

Este artigo descreve como lidar com erros em APIs de ASP.NET Core. A documentação para APIs Mínimas está selecionada. Para ver a documentação das APIs baseadas em controlador, selecione a guia Controllers. Para diretrizes de tratamento de erros, consulte Tratar erros em aplicativos Blazor do ASP.NET Core.

Página de Exceção do Desenvolvedor

A Página de Exceção do Desenvolvedor exibe informações detalhadas sobre exceções de solicitação sem tratamento. Ele usa para capturar exceções síncronas e assíncronas do pipeline HTTP e gerar respostas de erro. A página de exceção de desenvolvedor é executada no início do pipeline do middleware, para que ela possa capturar exceções sem tratamento lançadas no middleware subsequente.

Os aplicativos ASP.NET Core habilitam a página de exceção do desenvolvedor por padrão quando ambos estão presentes:

  • Em execução no ambiente .
  • O aplicativo foi criado com os modelos atuais, ou seja, usando .

Os aplicativos criados usando modelos anteriores, ou seja, usando , podem habilitar a página de exceção do desenvolvedor chamando .

Aviso

Não habilite a Página de Exceção do Desenvolvedor, a menos que o aplicativo esteja em execução no ambiente. Não compartilhe informações detalhadas de exceção publicamente quando o aplicativo for executado em produção. Para obter mais informações sobre como configurar ambientes, consulte ASP.NET Core ambientes de runtime.

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
  • Headers
  • Metadados de ponto de extremidade, se houver

A Página de Exceção do Desenvolvedor não tem garantia de fornecer nenhuma informação. Use o logging para obter informações completas de erro.

A imagem a seguir mostra um exemplo de página de exceção de desenvolvedor, com animação para mostrar as guias e as informações exibidas.

Página de exceção do desenvolvedor animada para mostrar cada aba selecionada.

Em resposta a uma solicitação com um cabeçalho, 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
  • APIs mínimas
  • Controladores

Para ver a página de exceção do desenvolvedor em uma API mínima:

  • Execute o aplicativo de exemplo no ambiente.
  • Acesse o endpoint.

Esta seção refere-se ao aplicativo de exemplo a seguir para demonstrar maneiras de lidar com exceções em uma API Mínima. Ele gera uma exceção quando o endpoint é 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();

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.

  • APIs mínimas
  • Controladores

Para configurar a chamada . Por exemplo, o código a seguir altera o aplicativo para responder com uma carga 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

  • APIs mínimas
  • Controladores

Considere o aplicativo de API Mínimo 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 endpoint gera uma representação de quando é maior que , caso contrário, gera um código de status sem corpo de resposta. Para obter mais informações sobre como criar uma resposta, consulte Criar respostas em aplicativos de API mínimos.

A configuração pode ser ajustada para produzir um conteúdo de corpo comum, quando vazio, para todas as respostas de cliente HTTP () ou servidor (). O middleware é configurado chamando o método de extensão UseStatusCodePages .

Por exemplo, 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, ). Para obter mais informações, consulte 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 da 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 nos registros a implementação padrão.

Em aplicativos ASP.NET Core, o middleware a seguir 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 compatíveis com o IProblemDetailsWriter registrado (padrão: application/json):

  • : gera uma resposta de detalhes do problema quando um manipulador personalizado não é definido.
  • : gera uma resposta de detalhes do problema por padrão.
  • : gera uma resposta de detalhes do problema no desenvolvimento quando o cabeçalho HTTP da solicitação não inclui .
  • APIs mínimas
  • Controladores

Aplicativos mínimos de API podem ser configurados para gerar a resposta de detalhes do problema para todas as respostas de erro do cliente HTTP e do servidor que ainda não têm conteúdo do corpo usando o método de extensão.

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 , consulte Detalhes do problema

Fallback IProblemDetailsService

No código a seguir, retornará um erro se a implementação não for capaz de gerar um :

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 não for possível gravar um arquivo. Por exemplo, um ponto de extremidade em que o cabeçalho de solicitação Accept especifica um tipo de mídia que não é compatível.
  • Utiliza o middleware de manipulador de exceções.

Observação

O [nome do sistema ou serviço] suporta os seguintes tipos de mídia no cabeçalho da solicitação:

  • application/json
  • application/problem+json
  • Tipos curinga, como e

Tipos de mídia que não são JSON, como ou , não são suportados e acionam o comportamento de fallback.

O exemplo a seguir é semelhante ao anterior, exceto pelo fato de chamar o .

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

Recursos adicionais de tratamento de erros

  • APIs mínimas
  • Controladores

Migração de controladores para APIs mínimas

Se você estiver migrando de APIs baseadas em controlador para APIs mínimas:

  1. Substituir filtros de ação por filtros de ponto de extremidade ou middleware
  2. Substituir validação de modelo por validação manual ou associação personalizada
  3. Substituir filtros de exceção por middleware de tratamento de exceção
  4. Configurar detalhes do problema usando respostas de erro consistentes

Quando usar o tratamento de erros baseado em controlador

Considere APIs baseadas em controlador se precisar.

  • Cenários complexos de validação de modelo
  • Tratamento centralizado de exceções entre vários controladores
  • Controle refinado sobre a formatação de resposta de erro
  • Integração com recursos do MVC, como filtros e convenções

Para obter informações detalhadas sobre o tratamento de erros baseados em controlador, incluindo erros de validação, personalização de detalhes do problema e filtros de exceção, consulte as seções da guia Controladores .

Recursos adicionais