ASP.NET Core - Usando a classe ProblemDetails - II
Hoje continuar a apresentar a classe ProblemDetails e mostrar como usá-la na ASP .NET Core. |
Continuando o artigo anterior vamos ver agora uma implementação de Problem Details usando o pacote Hellang.Middleware.ProblemDetails criado por Kristian Hellang que é um middleware que mapeia exceções para o Problem Details.
Usando Problem Details na ASP .NET Core
O middleware
ProblemDetails de Kristian Hellang trata as exceções que ocorrem no
pipeline de processamento do request e converte os detalhes da exceção para o
formato definido para o Problem Details na RFC 8707.
Para trabalhar com ProblemDetails, vamos instalar o pacote Nuget
Hellang.Middleware.ProblemDetails em nosso projeto.
Vamos criar um novo projeto usando o template ASP .NET Core Web API no VS 2022 chamado API_ProblemDetails segundo as configurações definidas a seguir:
Observe que vamos criar uma Web API usando controladores, sem usar as Minimal APIs, para focar na implementação do ProblemDetails.
Ao final teremos na janela Solution Explorer o projeto padrão criado com a estrutura a seguir:
Vamos agora instalar o pacote Hellang.Middleware.ProblemDetails no projeto usando o comando abaixo na janela do Package Manager Console do Visual Studio
Install-Package Hellang.Middleware.ProblemDetails
A seguir vamos configurar o middleware que acabamos de instalar. Geralmente isso era feito na classe Startup mas como no novo template essa classe não é mais criada então vamos realizar a configuração no arquivo Program.
1- Vamos registrar os serviços do
middleware no contêiner DI usando o método
AddProblemDetails();
2- Vamos incluir o middleware no pipeline usando o método
UseProblemDetails();
Abaixo temos o código configurando o Middleware:
using Hellang.Middleware.ProblemDetails; var builder = WebApplication.CreateBuilder(args);
// Add
services to the container. var app = builder.Build();
//
Configure the HTTP request pipeline. app.UseHttpsRedirection(); |
Com isso agora temos que as respostas de não exceção são convertidas em instâncias de ProblemDetails quando qualquer uma das seguintes condições for verdadeira:
Testando a implementação
Para testar a nossa implementação vamos incluir um novo método Get() no controlador WeatherForecast do projeto onde vamos lançar uma exceção retornando um BadRequest();
[HttpGet("{x}")] public ActionResult Get(int x) { int i = 0; try { i = 10 / x; } catch (Exception ex) { return BadRequest(); } return Ok(i); } |
Neste código, se o método Get receber um valor igual a 0 será lançada uma exceção capturada no bloco try/catch onde retornamos um BadRequest(). Executando projeto teremos o seguinte resultado:
Informando o valor 0 como parâmetro para o método Get teremos o resultado a seguir:
Podemos também criar uma instância da classe Microsoft.AspNetCore.Mvc.ProblemDetails
e passá-la de volta ao cliente. Para isso teremos que alterar o código do método
Get conforme o código mostrado abaixo:
[HttpGet("{x}")] public ActionResult Get(int x) { int i = 0; try { i = 10 / x; } catch (Exception ex) { var problemDetails = new ProblemDetails { Status = StatusCodes.Status400BadRequest, Type = "https://example.com/divisionbyzero", Title = "Divisão por zero...", Detail = ex.StackTrace, Instance = HttpContext.Request.Path }; return BadRequest(problemDetails); } return Ok(i); }
|
O resultado da execução será o seguinte:
Além disso, podemos personalizar o comportamento do middleware ProblemDetails usando ProblemDetailsOptions na configuração do serviço :
... builder.Services.AddProblemDetails(opts => { opts.IncludeExceptionDetails = (context, ex) => { var environment = context.RequestServices.GetRequiredService<IHostEnvironment>(); return environment.IsDevelopment(); }; }); ... |
Nesta opção de configuração estamos garantindo que os detalhes da exceção sejam incluídos apenas se você estiver no ambiente de desenvolvimento.
Se você desejar poderá também estender a classe ProblemDetails criando uma classe de exceções personalizada, veja abaixo um exemplo para uma exceção chamada CategoriaCustomException que herda de Exception e estende ProblemDetails:
public class CategoriaCustomException : Exception { public string AdditionalInfo { get; set; } public string Type { get; set; } public string Detail { get; set; } public string Title { get; set; } public string Instance { get; set; } public CategoriaCustomException(string instance) { Type = "categoria-custom-exception"; Detail = "Ocorreu um erro ao tratar a categoria"; Title = "Categoria Exception"; AdditionalInfo = "Tente acessar o serviço mais tarde..."; Instance = instance; } } |
Dessa forma vimos que é importante padronizar o tratamento de erros das exceções em nossas APIs e podemos fazer isso usando a classe ProblemDetails e temos também a alternativa de usar o middleware que implementa os mesmos recursos.
Em outro artigo iremos tratar com mais profundidade este importante recurso.
E estamos conversados...
"Pois estou
convencido de que nem morte nem vida, nem anjos nem demônios, nem o presente nem
o futuro, nem quaisquer poderes,nem altura nem profundidade, nem qualquer outra
coisa na criação será capaz de nos separar do amor de Deus que está em Cristo
Jesus, nosso Senhor."
Romanos 8:38,39
Referências: