Filtros são um recurso do ASP.NET que permite interceptar e executar lógica personalizada antes ou depois de determinadas etapas do ciclo de vida de uma requisição. Eles oferecem uma maneira eficaz de adicionar funcionalidades transversais (como autenticação, autorização, manipulação de resultados ou tratamento de erros) sem poluir a lógica de seus controladores ou ações.
Tipos de filtros no ASP.NET
O ASP.NET oferece vários tipos de filtros que podem ser aplicados em diferentes estágios do ciclo de vida de uma requisição:
Authorization Filters
O primeiro deles é o Authorization Filter, que determina se o usuário tem permissão para acessar um recurso específico. Eles são executados antes que qualquer outra parte da requisição seja processada.
Digamos que precisamos de um filtro de autorização para poder restringir o acesso de usuários a áreas administrativas da aplicação. Neste filtro, somente usuários com o nível de acesso de administrador podem acessar determinadas rotas.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
public class CustomAuthorizationFilter : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (!context.HttpContext.User.Identity.IsAuthenticated)
{
context.Result = new RedirectResult("/Account/Login");
return;
}
if (!context.HttpContext.User.IsInRole("Admin"))
{
context.Result = new ForbidResult();
}
}
}
No código acima, herdamos de “Attribute” para tornar a classe um filtro, sem precisar instanciá-la diretamente. A interface “IAuthorizationFilter” define a lógica de autorização antes da execução da ação, garantindo o acesso adequado.
A implementação do método verifica se o usuário está autenticado. Caso não esteja, ele é redirecionado para a tela de login. Se o usuário estiver autenticado, verificamos se ele possui a role “Admin”. Se a role não estiver registrada, o acesso é negado com um retorno de status 403 Forbidden.
Agora que a lógica do filtro foi criada, precisamos aplicar o filtro em um controller. Para isso, basta decorá-lo com o atributo correspondente. Isso garante que todas as actions dentro dessa controller sejam submetidas ao filtro antes de serem executadas:
[CustomAuthorizationFilter]
public class DashboardController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult Details()
{
return View();
}
}
Se você quiser aplicar o filtro apenas a uma action específica, pode decorá-la diretamente. Nesse caso, somente essa ação passará pelo filtro:
public class DashboardController : Controller
{
public IActionResult Index()
{
return View();
}
[CustomAuthorizationFilter]
public IActionResult Details()
{
return View();
}
}
Action Filters
Os Action Filters permitem executar lógica antes ou depois da execução de uma ação do controlador. Como exemplo podemos imaginar que seja necessário medir o tempo de execução de ações para identificar gargalos de desempenho na aplicação. Para isso, podemos criar o seguinte filtro.
public class LogExecutionTimeFilter : Attribute, IActionFilter
{
private readonly ILogger _logger;
private Stopwatch _stopwatch;
public LogExecutionTimeFilter(ILogger logger)
{
_logger = logger;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_stopwatch = Stopwatch.StartNew();
_logger.LogInformation($"Iniciando a execução da ação: {context.ActionDescriptor.DisplayName}");
}
public void OnActionExecuted(ActionExecutedContext context)
{
_stopwatch.Stop();
_logger.LogInformation($"Ação {context.ActionDescriptor.DisplayName} concluída em {_stopwatch.ElapsedMilliseconds}ms.");
}
}
No código acima, utilizamos o “Stopwatch” para medir o tempo de execução da ação. O método “OnActionExecuting” é chamado antes da execução da ação, iniciando a medição do tempo, enquanto o “OnActionExecuted” é chamado após a execução da ação, registrando o tempo total gasto.
Result Filters
Os Result Filters permitem modificar ou executar lógica antes ou depois que um resultado de ação (como um ViewResult ou JsonResult) é processado e enviado ao cliente. Eles são úteis para tarefas como modificar cabeçalhos de resposta ou padronizar o formato de saída.
using Microsoft.AspNetCore.Mvc.Filters;
public class AddCustomHeaderFilter : Attribute, IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add("X-Custom-Header", "Este e um cabecalho personalizado.");
}
public void OnResultExecuted(ResultExecutedContext context)
{
// Aqui você pode adicionar a lógica que desejar
}
}
Assim como no filtro anterior, temos dois métodos que são executados em momentos diferentes. O método “OnResultExecuting” é chamado antes que o resultado da ação seja processado, permitindo modificar o contexto da resposta antes de ser enviada ao cliente. Já o método “OnResultExecuted” é chamado após a execução do resultado, permitindo realizar ações adicionais, como limpeza ou modificação da resposta final.
Exception Filters
Os Exception Filters são usados para capturar e tratar exceções não tratadas que ocorrem durante a execução de uma ação ou resultado. Eles permitem padronizar o tratamento de erros, como log de exceções ou retorno de mensagens de erro personalizadas.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
public class CustomExceptionFilter : Attribute, IExceptionFilter
{
public void OnException(ExceptionContext context)
{
Console.WriteLine($"Exceção capturada: {context.Exception.Message}");
context.Result = new JsonResult(new
{
Message = "Ocorreu um erro inesperado. Por favor, tente novamente mais tarde."
})
{
StatusCode = 500
};
context.ExceptionHandled = true;
}
}
Registrando filtros globalmente
No ASP.NET Core você pode registrar filtros globalmente no método “AddControllers” no arquivo “Program.cs”. Para isso, você precisa adicionar os filtros na coleção “options.Filters”.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
options.Filters.Add();
options.Filters.Add();
options.Filters.Add();
options.Filters.Add();
});
No exemplo acima todos os filtros criados no artigo foram adicionados de forma centralizada. Dessa forma, eles serão executados em todas as requisições da aplicação, seguindo a ordem do ciclo de vida de execução dos filtros no ASP.NET Core.
Boas práticas
Ao utilizar filtros em ASP.NET Core, é importante seguir algumas boas práticas para garantir que seu código seja manutenível, reutilizável e eficiente. Aqui estão algumas recomendações:
Simplicidade: mantenha a lógica dentro dos filtros simples e objetiva. Evite implementar lógica complexa, pois filtros são executados frequentemente durante o ciclo de vida de uma requisição e podem impactar o desempenho e a legibilidade do código.
Reutilização: sempre que possível, crie filtros genéricos que possam ser reutilizados em várias partes da aplicação. Filtros genéricos são mais flexíveis e ajudam a reduzir a duplicação de código.
Evite repetições: utilize filtros globais para lógica comum, como autenticação, autorização ou logging, que devem ser executados em várias partes da aplicação. Isso ajuda a evitar a repetição de lógica nas controllers e ações.
Essas boas práticas visam melhorar a manutenibilidade e a escalabilidade da aplicação, garantindo que os filtros sejam eficientes e fáceis de gerenciar no futuro.
Acelere a sua carreira conosco!
Se você é Desenvolvedor .NET Júnior e quer acelerar sua carreira até nível Pleno com salário de R$7k+, ou mesmo busca a primeira vaga, conheça a Mentoria .NET Start: Clique aquiSe é Desenvolvedor .NET Pleno ou Sênior e quer virar referência técnica em sua equipe e mercado, com salário de R$10k+, conheça a Mentoria .NET Expert: Clique aqui
Conclusão
Filtros em ASP.NET oferecem flexibilidade e organização ao permitir lógica personalizada em diferentes etapas do ciclo de vida de uma requisição. Ao utilizar Authorization, Action, Result, e Exception filters, podemos lidar com autenticação, manipulação de resultados e tratamento de erros de forma elegante e modular. O uso de filtros personalizados melhora a manutenção do código e permite uma aplicação mais estruturada e limpa.