O ASP.Net MVC provê Action Filters que executam lógicas de filtragem antes ou depois que um Action Method é chamado. Action Filters são atributos personalizados que fornecem através de meios declarativos a possibilidade de adicionar um filtro que será executado para adicionar um comportamento aos métodos da Controller.
Action Filters fornecem uma técnica simples e poderosa de modificar ou melhorar o pipeline do ASP.Net MVC através da “injeção” de comportamento em determinados momentos ajudando a resolver diversas situações em algumas ou todas as partes da aplicação.
Os Action Filters são um dos tipos de filtros que o ASP.Net MVC 4 possui, estes filtros estão disponíveis para uso sem necessidade de customização, são eles:
- Authorization Filter – Segurança e controle de usuários autenticados
- Action Filter – Injeção de comportamento na execução de um ActionMethod
- Result Filter – Injeção de comportamento na execução de um ActionResult
- Exception Filter – Captura e tratamento na ocorrência de Exceptions
Um exemplo muito clássico do uso de Actions Filters é na Autorização de usuários logados:
[Authorize] public class AccountController : Controller { [AllowAnonymous] public ActionResult Login(string returnUrl) { ViewBag.ReturnUrl = returnUrl; return View(); } }
O uso dos Action Filters é feito decorando a Controller ou Action Method, no exemplo acima está sendo requerida a autorização de usuário para todos os métodos da Controller, caso isso seja necessário apenas para um método o Action Filter [Authorize] pode decorar apenas o método em questão, um exemplo disto é o próprio método de Login, pois nele é aplicado o filtro [AllowAnonymous] abrindo uma exceção para a regra geral aplicada na Controller.
O uso de Action Filters é muito comum, porém muitas vezes necessitamos de um comportamento diferenciado e nesses casos é possível criar o seu próprio Action Filter para definir um comportamento específico durante a chamada dos Actions Methods da aplicação.
Criando um Action Filter Customizado
O exemplo a ser abordado é muito simples, uma aplicação deve possuir um comportamento de exibir propagandas (conhecido como Advertising ou ADS) nas Views. Uma forma de atender este requisito é criando um Action Filter que fará este trabalho.
Roteiro
- Criar uma aplicação ASP.Net MVC 4 no Visual Studio chamada MvcFilterExample;
- Adicionar uma nova classe chamada ExibirAdsActionFilter na pasta Filters;
- Registrar o Action Filter de forma global ou utilizá-lo diretamente na Controller;
- Testar e validar o funcionamento do novo Action Filter.
A classe ExibirAdsActionFilter possui a seguinte estrutura
using System.Web.Mvc; namespace MvcFilterExample.Filters { public class ExibirAdsActionFilter : ActionFilterAttribute, IActionFilter { void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext) { filterContext.Controller.ViewBag.ConteudoAd = GerarConteudoAD(); } void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext) { AtualizarExibicaoAD(); } private string GerarConteudoAD() { return "<hr/><h2>Propaganda Aqui!<h2 /><hr/>"; } private void AtualizarExibicaoAD() { // Neste método pode ser executada uma atualização // do contador de exibições de determinada propaganda. } } }
Para construir o Action Filter proposto é necessário herdar a classe ActionFilterAttribute e implementar a interface IActionFilter.
A classe ActionFilterAttribute é a base para todos attribute filters, esta classe provê os seguintes métodos:
- OnActionExecuting (ActionExecutedContext filterContext): Chamado um pouco antes do Action Method.
- OnActionExecuted (ActionExecutingContext filterContext): Chamado após o Action Method e antes do Action Result ser executado (antes de renderizar a View).
- OnResultExecuting (ResultExecutingContext filterContext): Chamado um pouco antes do Action Result (antes de renderizar a View).
- OnResultExecuted (ResultExecutedContext filterContext): Chamado após o Action Result ser executado (após a View ter sido renderizada).
Pelo fato de estar sendo utilizada a interface IActionFilter apenas os métodos OnActionExecuting e OnActionExecuted necessitam ser implementados.
(Os últimos dois métodos atendem a filtros do tipo Result Filters e são implementados pela interface IResultFilter).
O exemplo é bem simples, o método OnActionExecuting gera o conteúdo de uma propaganda e armazena em uma ViewBag e o método OnActionExecuted contabiliza o número de visualizações.
Utilizando e Registrando Action Filters
Exitem 3 maneiras de utilizar este um novo Action Filter
- Manualmente em uma Controller (todos os Actions Methods farão uso do filtro)
- Manualmente nos Action Methods que farão uso do filtro
- Registrando globalmente o filtro na aplicação (a aplicação inteira irá usar o filtro)
Para utilizar manualmente o Action Filter basta adicionar a referência do namespace da classe do filtro e decorar a Contoller ou Action Method com [ExibirAdsActionFilter]
using System.Web.Mvc; // Referência das classes de filtro using MvcFilterExample.Filters; namespace MvcFilterExample.Controllers { // Usando o filtro para toda Controller [ExibirAdsActionFilter] public class ClienteController : Controller { // Usando o filtro para cada Action Method [ExibirAdsActionFilter] public ActionResult Index() { return View(); } } }
OBS – Uma vez que a Controller foi decorada com o uso do filtro, todos os Action Methods assumem esse comportamento, não é necessário decorá-los.
Para registrar globalmente o Action Filter é necessário modificar a classe FilterConfig dentro da pasta App_Start
using System.Web.Mvc; // Referência das classes de filtro using MvcFilterExample.Filters; namespace MvcFilterExample { public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); // Novo filtro adicionado filters.Add(new ExibirAdsActionFilter()); } } }
OBS – Ao registrar o Action Filter globalmente não é mais necessário manter a referencia MvcFilterExample.Filters e a decoração [ExibirAdsActionFilter] na Controller ou Action Methods, pois o registro aplicará o uso do filtro para toda a aplicação.
Para validar o funcionamento do filtro basta chamar o ViewBag ConteudoAd em uma View
<table> <tr> <td> @Html.Raw(@ViewBag.ConteudoAd) </td> </tr> </table>
Atente-se ao modo de utilização do filtro, se foi registrado globalmente ou se está sendo utilizada em uma Controller específica, caso a ViewBag seja chamada através de uma Controller que não utiliza o Filtro ela retornará vazia. Abaixo o resultado da chamada da ViewBag criada dinamicamente pelo Action Filter customizado para propagandas.
O Action Filter está implementado e em funcionamento.
Resumo
O uso de Action Filters customizados é muito comum e atendem a diversas necessidades rotineiras como:
- Validação de regras de acesso de usuários
- Log de atividades dos usuários
- Captura de IP ou outras informações do cliente
- Exibição de propagandas
- Tratamento e notificações de exceptions
Espero que seja útil!
Feedbacks ou dúvidas são sempre muito bem vindos e respondidos, utilize os comentários abaixo para continuarmos trocando informações.
como faço para passar uma variável para o construtor do filtro?
Andrey,
Segue exemplo:
FILTRO:
public class Log : ActionFilterAttribute
{
public bool LogarErro { get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
if (filterContext.Exception != null)
{
var MensagemErro = filterContext.Exception.Message;
if (LogarErro)
{
// Realizar gravação do erro
}
}
}
}
APLICAÇÃO:
[Log(LogarErro=true)]
public class HomeController : Controller
Consegui lhe ajudar?
Abraço!
Eduardo seria no caso para fazer assim:
string _teste = “valor”;
[Log(LogarErro=_teste)]
public ActionResult Cadastrar()
{ return View(); }
Se vc declarar a propriedade do filtro como String (assim como eu demonstrei no exemplo anterior) dá pra fazer tranquilo, pode testar que é sucesso 😉
so q o valor q eu desejo passar para o filtro so consigo pegar ele quando estou dentro da action. pois é um valor q vem do banco. att.
Por que apenas dentro da Action? Somente no momento da chamada da Action vc sabe qual dado buscar?
Se for um dado global independente da Action você pode criar uma Controller base que herda de Controller e fazer todas as outras controllers herdarem dela.
Ai nessa controller base você cria uma chamada que vai alimentar essa sua string que vai passar no filtro, entendeu?
Depende muito do que você quer fazer, o que importa é que vc precisa do dado antes de entrar na Action, se não fica sem sentido usar o filtro!
Bom Dia Eduardo
Primeiramente excelente pots
Preciso da sua ajuda numa coisa
Eu criei role especificas para cada operação exemplo:
Authorize(roles=”visualizar”)
action
Authorize(roles=”editar”)
action
por isso se o usuario não tiver autorização eu gostaria de enviar uma mensagem ao usuario através de uma viewBag
Exemplo “Acesso Restrito a essa funcionalidade”
Poderia me ajudar nesse caso?
Obg e Abrs…
Boa dia, parabéns pelo artigo, sabe me dizer se dessa forma consigo fazer um filtro para um site do tipo ecommerce?
Exemplo, esta aparecendo os produtos, ai quando clico em um valor de uma lista de valor, apenas o “miolo” da pagina muda e refaz o select da lista trazendo apenas com aquelas condições?
Ótimo post.