Tratamento de Exceções e Logging em ASP.NET Core com Injeção de Dependência e Pipeline

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.

  1. 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.

  1. 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" });
}

  1. 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");
    }
}

  1. 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.

  1. 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.

Tags: ASP.NET Core Injeção de Dependência middleware NLog Tratamento de Exceções

Publicado em 7-13 20:45