Validações cruzadas

Neste artigo do manual de ASP.NET MVC vamos falar sobre as validações cruzadas e as validações remotas, dois mecanismos adicionais aos já vistos para casos mais específicos.

Por Eduard Tomás - Tradução CRV


Publicado em: 11/7/12
Valorize este artigo:
Nos dois artigos anteriores do manual de ASP.NET MVC vimos como usar os atributos de Data Annotations para realizar validações e como criar nossas próprias validações tanto em servidor como em cliente.

Porém, há um cenário no que o uso de Data Annotations termina não se encaixando totalmente : as validações cruzadas. Ou seja, quando a validação de um campo depende do valor de outro campo. Assim, um campo pode ser obrigatório só se em outro campo se entrou um valor específico, ou então podemos ter dois campos mutuamente excludentes mas que em um dos dois deva ser informado sim ou sim. Certamente devem te ocorrer milhares de exemplos!

Tecnicamente usando Data Annotations (en ASP.NET MVC 3) é possível criar este tipo de validações, p.ex. el atributo Compare compara o valor de duas propriedades e falha se não forem iguais (se usa para o caso típico de entrar password e comprovar password em formulários de registro). Porém para cenários mais complexos que possam envolver várias propriedades, em casos em que seja necessário tratar o viewmodel como um todo, ASP.NET MVC proporciona um mecanismo muito simples e eficaz: a interface IValidatableObject.

IValidatableObject

Esta interface, que faz parte do .NET Framework 4, é usada pelo runtime de ASP.NET MVC para realizar as validações cruzadas. Tem um só método chamado Validate que deve retornar uma coleção de resultados de validação. Sua implementação é banal:

public class UsuarioViewModel : IValidatableObject
{
public string Nome { get; set; }
public string Password { get; set; }
public string CompararPassword { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrEmpty(Nome))
{
yield return new ValidationResult("Nao pode estar vazio.", new List<string> { "Nome" });
}
if (Password != CompararPassword)
{
yield return new ValidationResult("Devem ser iguais.", new List<string> { "Password", "CompararPassword" });
}
}
}

Listagem : Implementação de IValidatableObject

A chave deste método é que só retorna erros. Não retorna true ou false para indicar se tudo foi bem ou não. Simplesmente retorna uma coleção de todos os erros encontrados. Cada ValidationResult devolvido contém a mensagem de erro e (opcionalmente) uma lista com os nomes das propriedades envolvidas neste erro (a nível técnico de ASP.NET MVC podemos dizer que o valor que retornamos aqui se acrescenta à coleção Error de todas aquelas entradas do ModelState cuja chave esteja contida nesta lista de nomes de propriedades).

Dada esta implementação de IValidatableObject se o usuário deixa o nome vazio e entra dois passwords que não coincidem, o ModelState que o controlador recebe é:

Observe como o primeiro erro devolvido (que o nome não pode estar vazio) está associado à coleção “Errors” do elemento 0 do ModelState (cuja chave é “Nome”). Por outro lado, o erro de que as passwords devem ser iguais está associado tanto ao elemento 1 (Password) e 2 (CompararPassword) do ModelState, porque no método Validate o devolvemos associado a essas duas propriedades. Se forem usados os helpers para criar formulários (que já vimos neste manual) a tela mostrará todos os erros.

Em resumo, IValidatableObject proporciona um mecanismo rápido e simples para realizar validações cruzadas em nossos viewmodels.

Uma última observação a ter presente é que ASP.NET MVC só invoca o método Validate se as validações por atributos passaram. Ou seja, mesmo que só um atributo de Data Annotations falhe, o método Validate() não é invocado.

Validações remotas

O último tipo de validação que nos falta ver, é a validação remota. Esta validação é em cliente (de modo que como digo sempre é um tema de usabilidade e não de segurança) e consiste em chamar, usando Ajax, uma função de um controlador que nos indique se os valores atuais são corretos ou não. É pois uma maneira efetiva e rápida de realizar em cliente validações que exigem acessar recursos do servidor. P.ex. se poderia validar que um nome de um usuário não esteja registrado. Esta validação se realizaria em cliente mas implica executar um método do servidor (já que é onde se podem consultar todos os usuários da aplicação). o mecanismo de validações remotas de ASP.NET MVC torna muito fácil realizar estas validações ao se encarregar automaticamente de realizar todas as chamadas Ajax.

Habilitando a validação remota

Para habilitar a validação remota sobre uma propriedade de nosso viewmodel se usa um atributo de DataAnnotations, especificamente o atributo Remote. Seu uso é extremamente simples:

[Remote("ValidarNome", "Usuarios", ErrorMessage = "Nome inválido!")]
public string Nombre { get; set; }

Listagem : Uso do atributo [Remote] em uma propriedade

Basta indicar o nome da ação que deverá ser usada para validar (ValidarNome), o controlador e a mensagem de erro a ser mostrada. Opcionalmente, pode-se acrescentar um parâmetro HttpMethod que é o verbo http a usar para a chamada Ajax (se assume GET se não se coloca nada).

Agora só nos falta declarar a ação ValidarNome. Esta ação receberá como parâmetro o valor da propriedade que se valida (Nome no nosso caso) e deve retornar um booleano que indique se a validação foi bem (true) ou não (false). O único detalhe é que em lugar de devolver HTML, deve retornar um objeto JSON que contenha o valor booleano. Embora não tenhamos visto (ainda) como retornar algo que não seja HTML em ASP.NET MVC, retornar JSON é banal: basta usar o método Json e passar um objeto .NET que será serializado ao cliente em formato JSON. Assim, o código fica como:

[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public ActionResult ValidarNome(string nome)
{
return Json(!string.IsNullOrEmpty(nome) && "admin" != nome && "sa" != nome, JsonRequestBehavior.AllowGet);
}

Listagem : Ação usada para validação remota

Se você se pergunta para que serve o atributo [OutputCache] com que estamos decorando a ação é para que ASP.NET MVC envie os headers correspondentes de modo que esta resposta não possa ser cacheada. Logo falaremos em outro artigo sobre temas de caching em ASP.NET MVC. No momento, só vou comentar que é necessário que o inclua em todas as suas ações que você use para validações remotas, porque do contrário, sua resposta poderia ser cacheada!

E pronto, não é necessário fazer mais nada. Agora, à medida que o usuário vai entrando o nome este se valida usando a validação remota. Sim, sim, isso é uma solicitação http cada vez que o usuário pressiona uma tecla no campo de texto Nombe… Tenha isso em conta quando aplicar validações remotas.

Não nos aprofundaremos mais no assunto de validações remotas. Se você quiser, pode ler um post que coloquei sobre isso, há algum tempo, no meu blog: http://geeks.ms/blogs/etomas/archive/2011/01/14/asp-net-mvc3-validaci-243-n-remota.aspx

E lembre (correndo o risco de estar sendo chato ) que isso são validações em cliente. Não são para garantir a segurança de sua aplicação. São para melhorar a experiência de usuário.






Usuários :    login / registro

Manuais relacionados
Categorias relacionadas
O autor

Home | Sobre nós | Copyright | Anuncie | Entrar em contato