Atenção: esse artigo tem um vídeo complementar. Clique e assista!
Filters (filtros) é um recurso do ASP.NET MVC que permite a realização de operações antes ou após o processamento de requisições por Actions definidas em Controllers. Através dos mesmos, novos comportamentos podem ser inseridos em uma aplicação, estes que serão vistos no decorrer do artigo. Desta forma, você customiza o tratamento de solicitações enviadas por usuários.
Em que situação o tema é útil
O tema é útil para desenvolvedores que desejam trabalhar com recursos de autenticação/autorização de usuários, tratamento de erros, gravação de registros de log e caching de resultados dentro do framework ASP.NET MVC. Tais práticas geram preocupações com a segurança na manipulação de informações dentro de uma organização, além da performance da aplicação (a qual pode ser melhorada por meio do uso de caching).
Filters em ASP.NET MVC 3 - Customizando o processamento de requisições Web
Muitos desenvolvedores irão se deparar, durante o desenvolvimento de soluções para Web empregando a tecnologia ASP.NET MVC, com situações que exigirão a construção de algumas funcionalidades como controle de acesso, armazenamento de informações, dentre outros citados anteriormente. Em casos como estes, acaba sendo prática comum que tais recursos sejam implementados juntamente com a lógica de negócios do projeto considerado, gerando como possível consequência à duplicação de trechos de código, além de componentes de software estruturados de uma maneira que torna mais trabalhosa a realização de atividades de futuras manutenções. O objetivo do mecanismo conhecido como Filters é justamente ser uma alternativa a questões deste gênero, fornecendo uma série de implementações padrões que auxiliam os programadores em seu dia a dia, assim como permitir a geração de novos filtros customizados.
O ASP.NET MVC pode ser definido, em termos gerais, como um framework para a implementação de sites a partir da plataforma .NET. Esta tecnologia encontra-se atualmente na versão 3.0. É uma solução da Microsoft para a construção de soluções Web seguindo os padrões de arquitetura do MVC (Model – View – Controller). É compatível com a utilização de metodologias ágeis, nas quais seja possível a aplicação de técnicas de testes automatizados, conhecidas como TDD (Test Driven Development).
Considerando o contexto que envolve o desenvolvimento de aplicações voltadas para a Internet, é bastante comum a necessidade de implementar (com o decorrer de um novo projeto) uma série de funcionalidades não relacionadas diretamente às regras de negócio previstas para a solução. Constituem exemplos disto: a gravação de informações de log, o controle de acesso a determinados recursos de um sistema e o uso de caching.
TDD (Test Driven Development) é um método para desenvolvimento de software que prioriza, através de uma série de recomendações propostas por metodologias ágeis, a construção de soluções em um modo no qual as mesmas poderão ser facilmente integradas a ferramentas de execução automatizada de testes unitários. A adoção desta prática está condicionada à escrita de tais testes antes mesmo da codificação das partes da aplicação que serão submetidas aos mesmos.
Uma das principais vantagens em se atuar desta maneira é, sem sombra de dúvidas, assegurar um grau mínimo de testes na aplicação que está sendo elaborada.
Não são raros os cenários nos quais procedimentos de log ou de controle de acesso, por exemplo, são codificados dentro de trechos de código que correspondem às funcionalidades específicas de uma aplicação. Assim, a lógica resultante engloba tanto regras de negócio quanto aspectos genéricos. Esses não apresentando uma ligação direta com o objetivo primário que justificou a construção da solução. Esta falta de separação de responsabilidades acabará dificultando atividades futuras de manutenção, assim como poderá gerar empecilhos para a evolução do projeto em questão.
Procurando solucionar problemas deste gênero, o ASP.NET MVC disponibiliza um conjunto de recursos conhecido como Filters. Através do mesmo (já explicado anteriormente), você tem a possibilidade de condicionar se realmente será disparada uma ação ou mesmo, desempenhar um comportamento adicional que faz necessário em atendimento a algum requisito não funcional (questões envolvendo performance, segurança etc.).
A ideia do artigo é desenvolver uma aplicação em ASP.NET MVC e empregar os recursos de filters, bem como utilizar recursos do Entity Framework para o acesso a uma base de dados SQL Server, a biblioteca de scripts JQuery e o mecanismo de controle de acesso conhecido como ASP.NET Membership.
MemberShip é um provider do ASP.NET para trabalhar com a segurança de aplicações WEB. O mesmo está disponível desde a versão 2.0 do framework.
Visão geral dos Filters
Quando consideramos a arquitetura que caracteriza o funcionamento do ASP.NET MVC, Controllers desempenham um papel central: essas estruturas representam os dispositivos responsáveis pelo processamento de quaisquer tipos de requisições enviadas a uma aplicação Web. Já requisições devem ser compreendidas como ações disparadas como resultado da interação de usuários com recursos de um site (clicando sobre um link, preenchendo e enviando os dados de um formulário de cadastro etc.).
Controllers são classes que herdam do tipo básico Controller (o qual estende a classe ControllerBase), contendo um ou mais métodos que correspondem às Actions envolvidas no atendimento a solicitações.
Em termos práticos, Filters são classes que possibilitam a execução de uma lógica customizada antes ou ainda, após o processamento de uma Action. A Tabela 1 lista os quatros diferentes tipos de Filters disponibilizados pelo ASP.NET MVC. As interfaces citadas na mesma são a base para a construção de classes que definem comportamentos customizados.
Tipo de Filtro |
Interface |
Funcionamento |
Authorization Filters |
IAuthorizationFilter |
Executado logo no princípio, antes de outros filtros ou métodos responsáveis por uma Action, objetivando checagem de direitos de acesso de usuários (autorização). |
Action Filters |
IActionFilter |
Disparado antes ou depois da execução do método que corresponde a uma Action. |
Result Filters |
IResultFilter |
Este filtro é ativado antes ou depois do resultado de uma ação ser executada. |
Exception Filters |
IExceptionFilter |
Executado somente caso alguma das estruturas que compõem uma aplicação dispare uma exceção e não efetue o tratamento da mesma. |
Tabela 1. Tipos de Filters no framework MVC
Filters podem ser aplicados de diferentes maneiras em soluções que façam uso do framework MVC:
· De maneira declarativa, com a utilização de atributos que implementem alguma das quatros interfaces já citadas;
· Através da sobrecarga de métodos existentes no tipo Controller, sendo que os mesmos correspondem às operações declaradas nas quatro interfaces básicas;
· Registrando uma instância de objeto equivalente a um filtro dentro do método RegisterGlobalFilters do Global.asax da solução.
O uso de um atributo que representa um filtro pode acontecer tanto na definição (cabeçalho) da classe que equivale a um Controller (estendendo a lógica em questão a todas Actions que compõem essa estrutura), quanto por meio da associação de tal elemento à declaração de um método que corresponda a uma Action (fato este que caracteriza um comportamento mais específico). O ASP.NET MVC oferece por default algumas implementações listadas a seguir; o comum, nestes casos, é que sejam preenchidas as propriedades em instruções que contenham estes atributos, servindo como parâmetros para a execução dos filtros:
· AuthorizeAttribute: permite restringir o acesso a funcionalidades, utilizando mecanismos de autenticação/autorização;
· HandleErrorAttribute: possibilita o tratamento customizado de exceções propagadas durante o processamento de Actions;
· OutputCacheAttribute: disponibiliza meios para caching do resultado do processamento de Actions;
· RequireHttpsAttribute: obriga que requisições sejam enviadas via HTTPS, a fim de reforçar a segurança na transmissão de dados.
A classe abstrata Controller serve de base para o tratamento de requisições em uma aplicação MVC. Pelo fato deste tipo implementar as interfaces que caracterizam os diferentes filtros disponíveis. É possível que um Controller sobrecarregue algum dos métodos básicos, de maneira que esta ação introduza no processamento do mesmo a execução de um comportamento específico. Na Tabela 2 são apresentados tais métodos, assim como a maneira através da qual os mesmos operam.
Método |
Interface de Origem |
Funcionamento |
OnAuthorization |
IAuthorizationFilter |
Método empregado em atividades de controle de acesso. Tem por objetivo verificar se o usuário que desencadeou uma ação pode acessar recursos que está solicitando. |
OnException |
IExceptionFilter |
Operação executada quando uma exceção ocorre e não é tratada ao longo do processamento de uma Action. |
OnActionExecuting |
IActionFilter |
Chamado antes de iniciar o processamento de uma Action. |
OnActionExecuted |
Disparado depois do método que corresponde a uma Action ter sido invocada. |
|
OnResultExecuting |
IResultFilter |
Acionado antes do resultado de uma ação ser executada. |
OnResultExecuted |
Disparado após o resultado de uma ação ter sido executada. |
Tabela 2. Métodos da classe Controller que servem de base para a aplicação de Filters
É provável que existam cenários em que as ações desencadeadas por determinados filtros serão aplicáveis a todo um site. Componentes deste tipo são conhecidos como Global Filters. A definição de um filtro de escopo global acontece no arquivo Global.asax, dentro do método RegisterGlobalFilters: esta operação recebe como parâmetro um objeto do tipo GlobalFilterCollection, o qual corresponde a uma coleção responsável por armazenar todos os Global Filters ativos em uma aplicação. Instâncias de implementações padrões (como a classe HandleErrorAttribute) também podem ser empregadas neste caso.
Sob o ponto de vista arquitetural, filters correspondem à implementação de um termo conhecido em computação como crosscutting concerns ("interesses transversais"). Este conceito refere-se a funções genéricas, sem uma ligação direta com aspectos de negócio e cujo seu uso encontra-se disseminado ao longo de uma aplicação. Quando não implementadas de uma forma bem estruturada, a definição de funcionalidades deste tipo pode resultar em alguns problemas, tais como:
· Trechos duplicados por todo o código-fonte;
· Um alto acoplamento entre componentes de negócio e construções de finalidade mais geral (como mecanismos de tratamento de erro, por exemplo);
· Uma baixa coesão nas diversas classes e outras estruturas que compõem a solução, haja visto o fato de tais elementos acumularem atribuições que vão além do que se previu inicialmente para os mesmos.
A forma como os filters foram projetados dentro do ASP.NET, possibilita uma clara separação de responsabilidades entre classes relativas a funções de negócio e tipos que implementam aspectos básicos (como controle de acesso ou caching). Cada implementação default de filtro conta normalmente com uma classe-base, sendo que a centralização decorrente disto não apenas evita a repetição de código ao longo do projeto, como também contribui para a obtenção de componentes de software mais coesos e com um baixo acoplamento entre si, além de maximizar o potencial de reuso de funcionalidades de cunho mais genérico.
...