Neste artigo eu vou apresentar os filtros da ASP .NET Core MVC mostrando como funcionam e como usá-los. |
Os filtros são atributos anexados às classes ou métodos dos controladores que injetam lógica extra ao processamento da requisição e permitem a implementação de funcionalidades relacionadas a autorização, exception, log e cache de forma simples e elegante.
Os filtros permitem executar um
código personalizado antes ou depois de executar um método Action. Assim, eles
fornecem maneiras de realizar tarefas repetitivas comuns nos métodos Action e
são chamados em determinados estágios no pipeline de processamento de
solicitações.
Há muitos filtros internos disponíveis com o ASP.NET Core MVC e também podemos
criar filtros personalizados.
Como os filtros atuam ?
Os filtros são executados dentro do pipeline de invocação de ações do MVC, às vezes chamado de pipeline de filtros.
O pipeline de filtros é executado após o MVC selecionar a ação a ser executada.
fonte: https://docs.microsoft.com/pt-br/aspnet/core/mvc/controllers/filters
Tipos de Filtros na ASP .NET Core MVC
Cada tipo de filtro é executado em um estágio diferente no pipeline de filtro. Temos os seguintes tipos de filtro.
Tipo de Filtro | Descrição |
Authorization (Autorização) | Os filtros de autorização são executados primeiro. Esse filtro nos ajuda a determinar se o usuário está autorizado para o request atual. Pode causar curto-circuito em um pipeline se um usuário não for autorizado para o request atual. Também podemos criar um filtro de autorização personalizado. |
Resource (Recursos) | Os filtros de recursos tratam do request após a autorização. Podem executar código antes e depois do resto do filtro ser executado. Isso executa antes do model binding ocorrer. Pode ser usado para implementar o armazenamento em cache. |
Action (Ação) | Os filtros de ação executam o código imediatamente antes e depois do método Action do controlador ser chamado. Pode ser usado para executar qualquer ação antes ou depois da execução do método Action do controlador. Também podemos manipular os argumentos passados para uma Action. |
Exception (Exceção) | Os filtros de exceção são usados para manipular exceções ocorridas antes de qualquer coisa ser escrita no corpo da resposta. |
Result (Resultados) | Os filtros de Resultado são usados para executar o código antes ou depois da execução dos resultados de Actions individuais do controlador. Eles são executados somente se o método Action do controlador tiver sido executado com sucesso. |
O diagrama a seguir mostra como esses tipos de filtro interagem no pipeline de filtros.
fonte: https://docs.microsoft.com/pt-br/aspnet/core/mvc/controllers/filters
Implementação do filtros
Os filtros suportam dois tipos de implementação: síncrona e assíncrona.
Ambas as implementações usam
diferentes definições de interface, e, você deve escolher a implementação,
dependendo do tipo de tarefa que você precisa executar.
Os filtros síncronos
que executam código antes e depois do estágio do pipeline definem os métodos
OnStageExecuting e
OnStageExecuted.
Por exemplo, no ActionFilter.
O método OnActionExecuting
é chamado antes do método Action
ser invocado e o método OnActionExecuted
é chamado após o método Action retornar.
Exemplo de filtro Síncrono
using Microsoft.AspNetCore.Mvc.Filters;
namespace Filters { public class CustomActionFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { //Código : antes que a action executa } public void OnActionExecuted(ActionExecutedContext context)
|
Os
filtros assíncronos
são definidos apenas com um único método: OnStageExecutionAsync,
que usa um FilterTypeExecutingContext
e usa o delegate
FilterTypeExecutionDelegate
para executar o estágio do pipeline do filtro.
Por exemplo, em um ActionFilter,
o ActionExecutionDelegate
chama o método Action e podemos escrever o código antes e depois de chamarmos o
método Action.
Exemplo de filtro Síncrono
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters; namespace Filters
|
Podemos implementar interfaces
para vários tipos de filtro (estágio) em uma única classe.
Podemos implementar a versão síncrona ou a assíncrona de uma interface de
filtro, não ambas.
O .NET Framework verifica primeiro a interface do filtro assíncrono, se a
encontrar, ela é chamada. Se não for encontrada, chama o(s) método(s) da
interface síncrona. Se implementarmos ambos, a interface síncrona nunca será
chamada.
Escopo do filtro e ordem de execução
Um filtro pode ser adicionado ao
pipeline em um dos três escopos:
1- Pelo método
Action;
2- Pela classe do controlador;
3- Globalmente (é
aplicado a todos os controladores e actions). Para isso precisamos adicionar
o filtro na coleção MvcOptions.Filters
no método ConfigureServices;
Exemplo de filtro global
public void ConfigureServices(IServiceCollection services)
{ // Adiciona serviços do framework services.AddMvc(options=> { //adicionado por instância options.Filters.Add(new CustomActionFilter()); //adicionado por tipo options.Filters.Add(typeof(CustomActionFilter)); }); } |
Quando vários filtros são aplicados ao estágio específico do pipeline, o escopo do filtro define a ordem padrão da execução do filtro.
A ordem padrão de execução é a seguinte:
A figura abaixo mostra a ordem de execução padrão dos filtros:
Alterando a ordem de execução padrão
Podemos
substituir a seqüência padrão de execução do filtro implementando a interface
IOrderedFilter.
Essa interface expõe uma propriedade Order que tem precedência sobre o
escopo para determinar a ordem de execução.
Um filtro com um valor mais baixo de Order terá seu código anterior
executado antes que um filtro com um valor mais alto de Order. Um filtro
com um valor mais baixo de Order terá seu código posterior executado
depois que um filtro com um valor mais alto de Order.
Podemos definir a propriedade Order usando um parâmetro de construtor. Ex: [MeuFiltro(Name = "Controller Level Attribute", Order=1)]
Exemplo de alteração da ordem padrão de execução do filtro
1- Filtro MeuFiltro
using System;
using Microsoft.AspNetCore.Mvc.Filters; namespace Filters { public class MeuFiltroAttribute : Attribute, IActionFilter, IOrderedFilter { public int Order { get; set; } public void OnActionExecuting(ActionExecutingContext context)
public void OnActionExecuted(ActionExecutedContext context)
|
2- Controlador
using System;
using Microsoft.AspNetCore.Mvc; using Filters; namespace Filters.Controllers
|
Quando os filtros são executados no pipeline, os filtros são classificados primeiro por ordem e, em seguida, por escopo.
Todos os filtros internos são implementados pelo IOrderFilter e definem a ordem de filtro padrão como zero (0).
Cancelamento e curto-circuito
Você pode fazer um curto-circuito no pipeline de filtros a qualquer momento, definindo a propriedade Result no parâmetro context fornecido ao método do filtro. Por exemplo, o filtro de recurso a seguir impede que o resto do pipeline seja executado.
Exemplo de curto-circuito
using System; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters;
namespace FiltersSample.Filters public void OnResourceExecuted(ResourceExecutedContext context) |
Os filtros e a injeção de dependência (DI)
Os filtros podem ser adicionados por tipo ou por instância. Se você adicionar por instância, ela será usada para cada request. Se você adicionar por tipo, ele será ativado pelo tipo, o que significa que uma instância será criada para cada request e as dependências de construtor serão populadas pela DI (injeção de dependência).
Adicionar
um filtro por tipo é equivalente a usar o código:
filters.Add(new TypeFilterAttribute(typeof(MyFilter))).
Os filtros que são implementados como atributos e adicionados diretamente a
classes de controlador ou métodos Action não podem ter dependências de
construtor fornecidas pela DI (injeção de dependência). Isso ocorre
porque os atributos precisam ter os parâmetros de construtor fornecidos quando
eles são aplicados. Essa é uma limitação do funcionamento dos atributos.
Se seus filtros tiverem dependências que você precisa acessar a partir da
injeção de dependência, existem várias abordagens que você pode usar para
contornar essa limitação. É possível aplicar o filtro a um método Action ou
classe usando uma das opções a seguir:
1 - ServiceFilterAttribute;
Um ServiceFilter recupera uma instância do filtro da DI. Adicione o filtro ao contêiner em ConfigureServices e faça uma referência a ele em um atributo ServiceFilter.
2 - TypeFilterAttribute;
Um
TypeFilterAttribute é muito semelhante a ServiceFilterAttribute (e
também implementa IFilterFactory), mas seu tipo não é resolvido diretamente
pelo contêiner de DI. Em vez disso, ele cria uma instância do tipo usando
Microsoft.Extensions.DependencyInjection.ObjectFactory.
Devido a essa diferença, os tipos que são referenciados usando o
TypeFilterAttribute não precisam ser registrados com o contâiner primeiro
(mas eles ainda terão suas dependências atendidas pelo contêiner). Além
disso, TypeFilterAttribute também pode aceitar argumentos de construtor
para o tipo em questão.
3 - IFilterFactory implementado em seu atributo;
E assim, apresentei os conceitos básicos sobre filtros, mostrando os filtros internos, seu escopo, ordem de execução e cancelamento.
No próximo artigo veremos como implementar filtros.
"Deus nunca foi
visto por alguém. O Filho unigênito (Jesus), que está no
seio do Pai, esse o revelou."
João 1:18
Referências:
https://docs.microsoft.com/pt-br/aspnet/core/mvc/controllers/filters