Introdução

O tratamento de exceção é uma parte importante do desenvolvimento de software. Quando algo dá errado em uma aplicação, é importante ter um mecanismo para lidar com a exceção e fornecer um feedback adequado para o usuário. No Asp.Net Core, podemos usar o Middleware UseExceptionHandler para lidar com exceções globalmente em toda a aplicação. Neste post, vamos apresentar um tutorial detalhado sobre como implementar um controle de erros de forma simples em sua API.

Implementar um tratamento de erro global em uma API pode trazer uma série de benefícios significativos para o desenvolvimento e manutenção do seu aplicativo. Aqui estão alguns dos principais benefícios:

  • Padronização do tratamento de erro: ajuda a garantir que a abordagem de tratamento de erro seja igual em todos os endpoints e evita duplicação de código.
  • Resposta amigável ao usuário: Você pode retornar respostas amigáveis e compreensíveis aos usuários quando ocorrerem erros. Evite mensagens técnicas!
  • Segurança: Tratar erros de forma adequada ajuda a evitar a exposição de informações sensíveis ou detalhes técnicos aos usuários ou a pessoas mal-intencionadas.
  • Monitoramento e análise: Permite que você tenha uma visão geral dos tipos de erros que estão acontecendo com mais frequência.
  • Tratamento de exceções não previstas: Um tratamento de erro global permite capturar exceções não previstas.

Criando o Middleware

Para criar o Middleware de tratamento de exceção, crie uma nova classe e nomeie-a como TratamentoErroGlobal.cs. Em seguida, adicione o seguinte código:

public static class TratamentoErroGlobal{

    public static void AdicionarTratamentoErroGlobal(this IApplicationBuilder app)
    {
        app.UseExceptionHandler(applicationBuilder =>
        {
            applicationBuilder.Run(async contexto =>
            {
                contexto.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

                var erroNoRequest = contexto.Features.Get<IExceptionHandlerFeature>();

                if (erroNoRequest != null)
                {
                    var detalheProblema = new ProblemDetails
                    {
                        Status = (int)HttpStatusCode.InternalServerError,
                        Type = "Erro",
                        Title = "Erro no servidor",
                        Detail = "Ocorreu um erro interno."
                    };

                    await contexto.Response.WriteAsJsonAsync(detalheProblema);
                }
            });
        });
    }
}

Aqui está uma explicação sobre como essa classe funciona:

  1. public static void AdicionarTratamentoErroGlobal(this IApplicationBuilder app)
    • Isso define um método de extensão para a interface IApplicationBuilder que adiciona o Middleware de tratamento de erro global.
  2. app.UseExceptionHandler(applicationBuilder => { ... })
    • Aqui, o método UseExceptionHandler é chamado no IApplicationBuilder, configurando o Middleware de tratamento de exceção. O código dentro do bloco é uma função de Callback que lida com a exceção e cria uma resposta apropriada.
  3. contexto.Response.StatusCode = (int)HttpStatusCode.InternalServerError
    • Define o status code da resposta HTTP para 500 (InternalServerError) para indicar um erro no servidor.
  4. var erroNoRequest = contexto.Features.Get<IExceptionHandlerFeature>()
    • Obtém as informações sobre a exceção que ocorreu durante o processamento da requisição.
  5. var detalheProblema = new ProblemDetails{ ... }
    • Aqui, criamos um objeto ProblemDetails, que é uma classe padrão do ASP.NET Core usada para representar detalhes de um problema. Definimos o status, o tipo, o título e os detalhes do erro.
  6. await contexto.Response.WriteAsJsonAsync(detalheProblema)
    • Escreve a resposta como JSON contendo os detalhes do problema (representados pelo objeto ProblemDetails), utilizando o método assíncrono WriteAsJsonAsync.

Configurando a Injeção de Dependência do Middleware

Para configurar o Middleware de tratamento de exceção, precisamos adicionar o seguinte código em nossa classe Program.cs:

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

var app = builder.Build();
app.AdicionarTratamentoErroGlobal();
app.MapControllers();

app.Run();

O método AdicionarTratamentoErroGlobal é um método de extensão da classe TratamentoErroGlobal. Isso significa que ele estende a funcionalidade da interface IApplicationBuilder, permitindo adicionar um novo Middleware de tratamento de erros global à pipeline de processamento de solicitações do ASP.NET Core. Quando chamado no contexto da configuração da aplicação, ele configura o tratamento de erros global de forma apropriada.

Testando o Tratamento de Exceção Global

Para testar o tratamento de exceção global, podemos adicionar um código que gera uma exceção não tratada em uma de nossas Controllers. Quando executarmos a aplicação e acessarmos essa rota, o Middleware de tratamento de exceção retornará uma resposta em JSON para o usuário com os tratamentos que criamos anteriormente.

Crie uma classe chamada ExemploController.cs e adicione o seguinte código:

[ApiController]
[Route("api/exemplo")]
public class ExemploController : ControllerBase
{
    [HttpGet]
    public Task ObterExemplo()
    {
        throw new Exception("Exceção causada intencionalmente");        
    }
}

Podemos compilar e iniciar a API e, em seguida, através do Postman, fazer uma chamada GET para a rota http://localhost:[Porta]/api/exemplo. O retorno esperado deve ser o seguinte:

{
    "type": "Erro",
    "title": "Erro no servidor",
    "status": 500,
    "detail": "Ocorreu um erro interno."
}

Tratamento de Exceção Global no Asp.Net Core

Conclusão

O tratamento de exceção é uma parte importante do desenvolvimento de software. No Asp.Net Core, podemos usar o Middleware UseExceptionHandler para lidar com exceções globalmente em toda a aplicação. Neste post, vimos como configurar o Middleware de tratamento de exceção e devolver uma resposta personalizada para o usuário.

Esta abordagem apresenta os seguintes benefícios:

  • Simplicidade: UseExceptionHandler é simples de configurar. Você pode simplesmente fornecer um Middleware para tratamento de erros e o ASP.NET Core cuida do resto.
  • Recursos integrados: fornece suporte integrado para exibir páginas de erro amigáveis ao desenvolvedor ou retornar respostas de erro no formato JSON, dependendo do tipo de solicitação.
  • Consistência: por ser um recurso padrão do ASP.NET Core, ele garante uma abordagem consistente de tratamento de erros em diferentes partes do seu aplicativo.
  • Configuração centralizada: você pode configurar facilmente o tratamento de erros em um só lugar, facilitando o gerenciamento e a atualização.

Como contras desta abordagem, destaco o seguinte:

  • Customização limitada: embora forneça algumas opções de personalização, UseExceptionHandler pode não cobrir todos os cenários específicos de tratamento de erros que seu aplicativo exige.
  • Controle de log limitado: você pode ter controle limitado sobre como os erros são logados. O comportamento de log personalizado pode exigir soluções alternativas adicionais.

Em resumo, se as necessidades de tratamento de erros do seu aplicativo puderem ser atendidas pelos recursos fornecidos pelo UseExceptionHandler Middleware, é uma abordagem conveniente e direta. Por outro lado, se você precisar de mais controle, personalização e flexibilidade, construir um Middleware customizado implementando a interface IMiddleware pode ser a melhor escolha (e tema para um próximo post). Tenha em mente a complexidade da sua aplicação, a familiaridade da sua equipe com a tecnologia e as considerações de manutenção a longo prazo ao tomar esta decisão.

Referências

Rodrigo Bitencourt

Moro em São Caetano do Sul (SP). Sou Dev .NET, gosto de assuntos de Desenvolvimento Ágil e Arquitetura de Software. Curto viagens, natureza, fugir pro mato, fazer trilhas e acampar com meus filhos.