Esse post fecha uma série de posts sobre Action Filter, segue os links dos posts anteriores.
Recursos para criação de Custom Filter
ASP.NET MVC – Action Filters
ASP.NET MVC – Entendendo os Actions Filters
Para facilitar a criação de um Custom Filter o time de desenvolvimento do framework ASP.NET MVC criou a classe abstrata ActionFilterAttribute essa classe implementa as interfaces IActionFilter, IResultFilter que já discutimos anteriormente, para construir esse exemplo vamos utilizar essa classe.
A implementação dos métodos dentro da classe ActionFilterAttribute utiliza o modificador virtual permitindo assim que você sobrescreva somente os métodos que você precisa para criação do seu Filter, veja a assinatura dos métodos da classe abaixo:
public virtual void OnActionExecuting(ActionExecutingContext filterContext)
public virtual void OnActionExecuted(ActionExecutedContext filterContext)
public virtual void OnResultExecuting(ResultExecutingContext filterContext)
public virtual void OnResultExecuted(ResultExecutedContext filterContext)
Vamos criar um exemplo do zero, nesse exemplo vou criar uma aplicação simples e vou focar na criação do Filter,vamos criar uma aplicação de votação e o objetivo do nosso Filter será bloquear votos de um mesmo IP.
Criando a aplicação
No primeiro passo vamos criar um pequeno banco de dados para salvar os votos, veja a estrutura abaixo.
Imagem 1 - Banco de dados.
Veja abaixo o código do repositório, para esse exemplo estou utilizando o EF.
public class VotoRepositorio
{
VotacaoEntities entidades = new VotacaoEntities();
public void Salvar(Voto voto)
{
entidades.AddToVoto(voto);
entidades.SaveChanges();
}
public IEnumerable<Voto> ObterTodos()
{
return (from votos in entidades.Voto
select votos).AsEnumerable();
}
public IEnumerable<Voto> ObterIPUsuario(string ip)
{
return (from votos in entidades.Voto
where votos.IPUsuario == ip
select votos).AsEnumerable();
}
}
Criando o Custom Filter
Agora podemos iniciar a criação do Filter veja o código abaixo.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class VotacaoFilterAttribute : ActionFilterAttribute
{
VotoRepositorio votoRepositorio = new VotoRepositorio();
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Recupera IP do usuário
var ip = filterContext.HttpContext.Request.ServerVariables["REMOTE_ADDR"];
//Verifica se Action possui parâmetros
if (filterContext.ActionParameters.Count > 0)
{
//Se não encontrar nenhum voto com o IP atual permite a execução da Action.
if (votoRepositorio.ObterIPUsuario(ip).Count() == 0)
{
//Recupera o parâmetro Voto da Action.
Voto voto = filterContext.ActionParameters
.Where(x => x.Key == "voto").FirstOrDefault().Value as Voto;
//Seta a propriedade IP.
if (voto != null)
voto.IPUsuario = ip;
}
//Calcela a execução da Action caso já exista voto com IP atual
else
{
filterContext.Result = new ContentResult()
{
Content = String.Format("Esse IP: {0} já registrou um voto!", ip)
};
}
}
}
}
O código acima herda da classe ActionFilterAttribute e sobrescreve o método OnActionExecuting, o atributo AttributeUsage define que esse Filter pode ser utilizado somente em métodos e classes. O código do método OnActionExecuting recupera o IP do usuário e compara com todos os IPs cadastrados, caso o IP já possua um voto a seguinte mensagem será exibida no browser “Esse IP: xxx.xxx.xxx já registrou um voto!” e a execução da Action será cancelada , caso contrário recupero o objeto Voto e atualizo a propriedade IPUsuario.
Criando o Controller e as Views
Abaixo segue o código do Controller "Voto".
[HandleError]
public class VotoController : Controller
{
VotoRepositorio votoRepositorio = new VotoRepositorio();
public ActionResult Index()
{
//Mostra a View Index com todos os votos registrados.
return View(votoRepositorio.ObterTodos());
}
public ActionResult Votar()
{
return View();
}
[VotacaoFilter]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Salvar(Voto voto)
{
//Salva voto e mostra a View Index com todos os votos registrados
voto.DataVoto = DateTime.Now;
votoRepositorio.Salvar(voto);
return Redirect("Index");
}
}
Note que a action Salvar foi "decorada" com o nosso Filter VotacaoFilterAttribute isso porque ela é a responsável por salvar os votos do usuário.
Para finalizar falta apenas construir duas Views, a "Index" que vai listar todos os votos cadastrados e a "Votar" que possui um formulário com as opções de voto, veja o código completo das duas views abaixo.
Imagem 2 - Código da View Index.
Imagem 3 - Código da View Votar.
Conclusão
Esse é um recurso extremamente poderoso que pode ser utilizado em vários cenários, sempre que você tiver um código que deve ser executado antes, durante ou depois da execução de uma Action você pode criar um Filter, a reutilização de código também é um ponto importante imagine colocar um if em todas as Action para fazer uma verificação comum, como por exemplo verificar se o usuário tem permissão, simplesmente horrível para evitar esse horror utilize os Filter e se não existir um que atenda a sua necessidade crie um!
Baixe o código fonte em C# ou VB.NET
Daniel Fonseca Castro