Introdução
Em sistemas corporativos, o tratamento de exceções é uma tarefa essencial para desenvolvedores, refletindo diretamente a maturidade técnica na gestão de aplicações. Este artigo demonstra como implementar captura global de exceções em uma Web API com ASP.NET Core, utilizando o componente NLog para registro de logs. Serão abordados dois métodos distintos: filtros de serviço e middleware no pipeline, com exemplos práticos para ilustrar a integração.
- Configuração Inicial do Projeto
Para iniciar, crie um projeto ASP.NET Core Web API. Selecione o template de API e configure o ambiente de desenvolvimento. Certifique-se de que o projeto esteja devidamente estruturado e funcional antes de prosseguir.
- Simulação de Exceções
Para demonstrar o comportamento padrão, introduza uma exceção deliberada em um controlador. Por exemplo, lance uma exceção dentro de um método de ação. Observar o tratamento em diferentes ambientes de execução (Desenvolvimento vs. Produção) é crucial para entender a necessidade de uma abordagem personalizada.
[HttpGet]
public IActionResult ObterDados()
{
throw new InvalidOperationException("Erro simulado para demonstração");
return Ok(new[] { "dado1", "dado2" });
}
- Método 1: Exceção via Filtro de Serviço
Esta abordagem utiliza filtros de exceção globais, comuns em aplicações MVC tradicionais. Crie uma classe que implemente IExceptionFilter para interceptar exceções.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
public class FiltroExcecaoGlobal : Attribute, IExceptionFilter
{
private readonly ILogger _logger;
private readonly IHostEnvironment _ambiente;
public FiltroExcecaoGlobal(ILogger<filtroexcecaoglobal> logger, IHostEnvironment ambiente)
{
_logger = logger;
_ambiente = ambiente;
}
public void OnException(ExceptionContext contexto)
{
var excecao = contexto.Exception;
var detalhesErro = MontarDetalhesExcecao(excecao);
_logger.LogError(detalhesErro);
var resultado = new ContentResult
{
StatusCode = 500,
ContentType = "application/json;charset=utf-8;"
};
if (_ambiente.IsDevelopment())
{
var resposta = new { mensagem = excecao.Message, detalhes = detalhesErro };
resultado.Content = JsonConvert.SerializeObject(resposta);
}
else
{
resultado.Content = JsonConvert.SerializeObject(new { mensagem = "Ocorreu um erro interno." });
}
contexto.Result = resultado;
contexto.ExceptionHandled = true;
}
private string MontarDetalhesExcecao(Exception ex)
{
var sb = new System.Text.StringBuilder();
while (ex != null)
{
sb.AppendLine($"Erro: {ex.Message} | Rastreamento: {ex.StackTrace}");
ex = ex.InnerException;
}
return sb.ToString();
}
}
</filtroexcecaoglobal>
Registre o filtro no contêiner de injeção de dependência dentro de Startup.cs. Configure também o NLog para persistência de logs em arquivos.
public void ConfigureServices(IServiceCollection servicos)
{
servicos.AddScoped<FiltroExcecaoGlobal>();
servicos.AddControllers();
}
public void Configurar(IApplicationBuilder app, IHostEnvironment env, ILoggerFactory fabrica)
{
fabrica.AddNLog();
var caminhoNlog = Path.Combine(env.ContentRootPath, "nlog.config");
NLog.LogManager.LoadConfiguration(caminhoNlog);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapControllers());
}
Aplique o filtro ao controlador desejado usando o atributo [ServiceFilter].
[ServiceFilter(typeof(FiltroExcecaoGlobal))]
[ApiController]
[Route("api/[controller]")]
public class ControladorDados : ControllerBase
{
[HttpGet]
public IActionResult ObterDados()
{
throw new InvalidOperationException("Erro no controlador");
}
}
- Método 2: Exceção via Middleware no Pipeline
Utilize o middleware do pipeline ASP.NET Core para capturar exceções de forma centralizada. Implemente uma classe de middleware que envolva a execução da solicitação em um bloco try-catch.
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
public class MiddlewareExcecao
{
private readonly RequestDelegate _proximo;
private readonly ILogger _logger;
private readonly IHostEnvironment _ambiente;
public MiddlewareExcecao(RequestDelegate proximo, ILogger<middlewareexcecao> logger, IHostEnvironment ambiente)
{
_proximo = proximo;
_logger = logger;
_ambiente = ambiente;
}
public async Task Invocar(HttpContext contexto)
{
try
{
await _proximo(contexto);
}
catch (Exception excecao)
{
await TratarExcecao(contexto, excecao);
}
}
private async Task TratarExcecao(HttpContext contexto, Exception excecao)
{
contexto.Response.StatusCode = 500;
contexto.Response.ContentType = "application/json;charset=utf-8;";
var detalhes = GerarRelatorioExcecao(excecao);
_logger.LogError(detalhes);
object resposta;
if (_ambiente.IsDevelopment())
{
resposta = new { mensagem = excecao.Message, detalhes };
}
else
{
resposta = new { mensagem = "Erro interno do servidor." };
}
var json = JsonConvert.SerializeObject(resposta);
await contexto.Response.WriteAsync(json);
}
private string GerarRelatorioExcecao(Exception ex)
{
var lista = new List<string>();
while (ex != null)
{
lista.Add($"Exceção: {ex.Message}");
ex = ex.InnerException;
}
return string.Join(" | ", lista);
}
}
</middlewareexcecao>
Integre o middleware ao pipelinne em Startup.cs. Certifique-se de posicioná-lo corretamente para capturar exceções de todo o aplicativo.
public void Configurar(IApplicationBuilder app, IHostEnvironment env, ILoggerFactory fabrica)
{
fabrica.AddNLog();
NLog.LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration("nlog.config");
app.UseMiddleware<MiddlewareExcecao>();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapControllers());
}
Com o middleware ativo, qualquer exceção não tratada nos controladores será capturada e registrada no log. Os detalhes do log incluem informações da exceção e são gravados em arquivos conforme a configuração do NLog.
- Configuração do NLog para Persistência de Logs
Para ambos os métodos, utilize o NLog para gravar logs em arquivos. Crie um arquivo nlog.config na raiz do projeto com regras de destino.
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true">
<targets>
<target name="arquivoErro" xsi:type="File"
fileName="logs/erros-${shortdate}.log"
layout="${longdate} ${level} ${message} ${exception}" />
</targets>
<rules>
<logger name="*" minlevel="Error" writeTo="arquivoErro" />
</rules>
</nlog>
Esta configuração garante que erros sejam registrados em arquivos diários, facilitando a auditoria e depuração.