.NET - Tratamento global de exceções
O tratamento de exceções é uma das tarefas mais importantes no ciclo de desenvolvimento de uma aplicação robusta. |
Hoje veremos uma forma efetiva de realizar o tratamento de exceções usando o .NET 6 com aplicações ASP .NET Core.
Capturar e tratar erros(exceções) é uma das tarefas obrigatórias para todo o programador, e um dos recursos oferecidos para fazer isso na linguagem C# é o bloco try-catch.
O bloco try-catch-finally é usado para envolver o código onde existe a possibilidade de uma exceção/erro ocorrer e é constituído das seguintes seções :
Estrutura do bloco try-catch :
Try 'Código que pode gerar um erro. Catch 'Código para tratamento de erros. Finally 'Código de execução obrigatória. End Try |
Tratando exceções com o bloco try-catch
Usar o bloco try-catch é a abordagem básica e tradicional para realizar o tratamento de exceções. Para mostrar a sua utilização temos a seguir um trecho de código de um projeto ASP .NET Core Web API:
[Route("[controller]")] [ApiController] public class ProdutosController : ControllerBase { private readonly AppDbContext _context; private readonly ILogger<ProdutosController> _logger;
public
ProdutosController(AppDbContext context,
[HttpGet]
var produtos = _context.Produtos.ToList(); |
Neste código temos o endpoint definido no método GetProdutos que retorna uma lista de produtos onde temos um bloco try-catch que vai tratar possíveis erros que ocorram no código definido dentro do bloco try e exibir a mensagem : "Erro ao acessar produtos" ao usuário.
Abaixo temos um exemplo de acesso ao endpoint da API usando o Postman e o erro obtido sendo capturado e exibido :
Examinando a janela OutPut no Debug temos as mensagens de Log exibidas conforme esperado:
Temos assim um exemplo de try-catch que funciona e que é uma abordagem muito boa para o desenvolvimento para quem esta iniciando. Entretanto, esta abordagem tem uma desvantagem quando usada em grandes projetos : a quantidade de código que deve ser incluída.
Imagine que você tem um projeto com 10 controladores e que cada controlador possua 10 métodos onde você vai precisar incluir o bloco try-catch para tratar os erros.
Além do grande trabalho braçal que você vai ter que fazer incluindo centenas de linhas de código isso vai aumentar a probabilidade de erros e acaba se tornando um código repetitivo.
Aqui vai entrar a segunda abordagem para realizar o tratamento de erros.
Tratamento de erros global com middleware customizado
Essa é uma abordagem boa e eficaz para lidar com o nível global de exceção.
Podemos capturar todas as exceções não tratadas usando um manipulador de exceção em um único lugar e não vamos precisar usar o bloco try-catch nos métodos dos controladores. Para isso precisamos criar um middleware customizado que vai fazer o tratamento de exceções.
Vamos criar uma pasta Middlewares no projeto e nesta pasta vamos criar a classe ExceptionHandlingMiddleware:
public class
ExceptionHandlingMiddleware public async
Task InvokeAsync(HttpContext httpContext)
var errorResponse = new ErrorResponse |
Temos acima o código do middleware personalizado para lidar com as exceções. Nesse caso, primeiro, precisamos registrar ILogger e RequestDelegateservices usando a injeção de dependência.
O parâmetro
_next do tipo
RequestDeleagate é um delegate de função que pode lidar com nossas
solicitações HTTP. Além disso, o delegate de solicitação é passado para o
middleware e isso é processado pelo middleware ou passado para o próximo
middleware na cadeia.
Se a solicitação não for bem-sucedida, pode haver uma exceção e o método
HandleExceptionAsync será executado para capturar a
exceção de acordo com o tipo de exceção. Nesse caso, você pode alternar
instruções para identificar o tipo de exceção e, em seguida, podemos usar o
código de status adequado de acordo com a exceção como um exemplo de código
acima.
Além disso, não precisamos passar as mensagens de exceção para o lado do cliente do projeto. Nesse caso, poderíamos passar a mensagem personalizada e usar o ILogger para registrar a mensagem de exceção como um erro. Então poderíamos identificar a mensagem de exceção verificando os logs.
O código também usa a classe ErrorResponse e temos que criar esta classe na pasta Models:
public class ErrorResponse { public bool Success { get; set; } public string? Message { get; set; } } |
Agora só falta habilitar o middleware criado na classe Program:
... var app = builder.Build(); // Configure the HTTP request
pipeline. app.UseMiddleware<ExceptionHandlingMiddleware>(); app.UseHttpsRedirection(); |
A seguir vamos ajustar o código no controlador ProdutosController removendo os blocos try-catch e definindo o código como abaixo:
[Route("[controller]")] [ApiController] public class ProdutosController : ControllerBase { private readonly AppDbContext _context; private readonly ILogger<ProdutosController> _logger;
public
ProdutosController(AppDbContext context, ILogger<ProdutosController>
logger)
[HttpGet]
var produtos = _context.Produtos.ToList();
if (produtos.Count == 0)
throw new Exception("Erro ao acessar
produtos");
[HttpGet("{id:int}", Name = "ObterProduto")] |
Neste código definimos apenas dois métodos para testar a implementação do nosso middleware customizado onde estamos lançando exceções para retornar todos os produtos e para obter um produto pelo id quando o valor do id não for encontrado.
Os resultados obtidos usando o Postman podem ser vistos abaixo:
1- Obter todos os produtos
2- Obter um produto pelo seu Id
A abordagem de usar um middleware customizado para tratamento de erros é muito boa para grandes projetos e evita que você tenha que usar os blocos try-catch em todos os métodos dos seus controladores.
Isso aumenta a legibilidade do código, mantém o seu código limpo e mais fácil de ser reutilizado e continua realizando o tratamento de exceções.
Pegue o projeto aqui: TrataErroGlobal.zip
"Jesus dizia a todos: "Se alguém quiser
acompanhar-me, negue-se a si mesmo, tome diariamente a sua cruz e siga-me."
Lucas 9:23
Referências:
ASP .NET - Gerando QRCode com a API do Google