Tratamento de Exceção Global no Asp.Net Core
Tags: dotnet, braziliandevs, tutorial, csharp
Published: 2023-09-05 01:14:17

## 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:

```csharp
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_:

```csharp
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:

```csharp
[ApiController]
[Route("api/exemplo")]
public class ExemploController : ControllerBase
{
    [HttpGet]
    public Task<IActionResult> 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:

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

![Retorno do Tratamento de Erro Global da API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/frbr7cr5bej1710zai9c.png)

## 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
- [Como lidar com erros em APIs Web do ASP.NET Core](https://learn.microsoft.com/pt-br/aspnet/core/web-api/handle-errors?view=aspnetcore-8.0)
- [Asp.Net Core Middlewares](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-7.0)
- [Repositório do Github - Rodrigo Schemes Bitencourt](https://github.com/rodrigo-schemes/aspnetcore-tratamento-erro-global)