Validações em ASP.NET MVC

Vamos ver o que são as validações em ASP .NET MVC e como utilizá-las de uma forma efetiva.

Por Eduard Tomás - Tradução CRV


Publicado em: 04/6/12
Valorize este artigo:
Nos dois artigos anteriores vimos como enviar dados a um controlador usando POST y como gerar os formulários usando os helpers. Introduzimos também o conceito de Model Binding (como ASP.NET MVC era capaz de construir um objeto que recebia o controlador a partir dos dados da solicitação) e vimos como ao usar os helpers obtínhamos gratuitamente algumas validações, p.ex. se declarávamos um campo como int, ASP.NET MVC comprovava que não entrássemos caracteres alfanuméricos.

Na verdade, o que vemos automaticamente ao usar os helpers não são validações, são erros. Se introduzimos uma cadeia alfanumérica em um campo que foi declarado como int, quando o Model Binder deve conectar os dados gera um erro. Os erros que o Model Binder encontra ao tentar conectar os valores da request com as propriedades do viewmodel são salvos no ModelState e podem ser consultados a partir do próprio controlador e também da visão. Na verdade, como vimos no artigo anterior, os helpers consultam o ModelState para usar uma classe CSS específica no caso de que haja algum erro associado com o campo.

Tentar converter uma cadeia alfanumérica em um int é, portanto, um erro. Mas há muitos outros casos em que nos pode interessar dizer ao usuário que os dados entrados são incorretos: campos obrigatórios, cadeias com um determinado formato (p.ex. um email) ou dois campos que devem ter o mesmo valor (p.ex. senha e comprovar senha). São esses casos quando nos referimos a validações e é o que vamos tratar em nosso artigo. Porém, embora nós diferenciemos entre erros e validações ASP.NET MVC não o faz: ambos são tratados igual, ou seja, ambos são salvos no ModelState. Porém, antes de aprofundar mais, vejamos exatamente o que é o ModelState.

ModelState ou estado do modelo

O ModelState é um objeto, gerenciado pelo framework de ASP.NET MVC que indica qual é o estado do modelo. Neste contexto por modelo entendemos o objeto que recebe um controlador (o que geralmente chamamos view model) e por estado entendemos se é correto ou não. Correto significa que os dados da solicitação eram válidos e que o Model Binder pode criar um objeto e preenchê-lo. Incorreto significa que havia algum dado da solicitação inválido, seja por algum erro (uma cadeia alfanumérica tentou atribuir um int) ou então por alguma validação falida (uma cadeia declarada como email não tinha o formato correto).

O ModelState é basicamente um dicionário onde:

  1. As chaves são os nomes das propriedades de nosso modelo (realmente são os nomes que o Model Binder usa para lincar as propriedades mas podemos assumir que coincidem).
  2. Para cada chave há o valor que o Model Binder atribuiu a essa chave e o que mais nos importa: uma coleção dos erros vinculados a essa chave, se existirem. E quando aqui digo erros me refiro tanto a erros como a validações falidas.

Figura 1: ModelState com um erro

A Figura 1 mostra a composição do ModelState. A propriedade Keys contém as chaves (neste caso o viewmodel que estávamos usando era uma classe com uma propriedade cadeia Nome e um int chamado Idade) e a propriedade Values onde podemos ver, por cada chave, o valor que foi atribuido (Value) e a coleção de erros (Errors).

O ModelState contém uma propriedade chamada IsValid que nos diz se o modelo é correto, ou seja, se não há erros. Essa propriedade costuma ser usada da seguinte forma:

[HttpPost]
      public ActionResult Index(DemoModel data)
      {

           if (!ModelState.IsValid)
           {
                 return View(data);
            }
           else
           {
                 // Codigo normal
           return View("ok");
            }

     }

Se o ModelState não é válido significa que alguma entrada do usuário não é correta, porttanto devolvemos de novo a visão que contém o formulário com os dados. Como vimos no artigo anterior se usamos os helpers para criar o formulário, esses mostrarão os erros (em cor vermelha com a CSS por padrão). Se o ModelState é válido isso significa que as entradas do usuário são corretas de modo que procedemos a realizar a ação que quisermos.

Acrescentar nossas validações

Bom, vimos o mecanismo que o framework de MVC usa para nos indicar que há algum erro, o ModelState. Agora vamos ver como podemos acrescentar nossas validações. Embora ASP.NET MVC seja muito flexível neste ponto, vamos ver a forma mais comum de fazê-lo: usando DataAnnotations. Em artigos posteriores veremos outras formas.

Para acrescentar validações usando DataAnnotations simplesmente devemos decorar a propriedade que desejemos com algum dos atributos (alguns se encontram no namespace System.ComponentModel.DataAnnotations e outros em System.Web.Mvc). P.ex. se tivermos o seguinte viewmodel:

public class DemoModel
      {
            public string Nome { get; set; }
           public int Idade { get; set; }
     }

Se quisermos que o Nome seja obrigatório podemos decorá-lo com [Required]:

public class DemoModel
      {
            [Required]
           public string Nome { get; set; }
            public int Idade { get; set; }
     }

E pronto! Só com acrescentar o atributo Required, o framework sabe que o Nome é requerido e se o usuário não o entra se mostrará um erro:


Figura 2: O erro gerado por [Required]

Se você comparar a Figura 2 com as capturas de tela do artigo anterior onde também eram mostrados campos errados, verá uma pequena diferença: não apenas se mostra o campo em vermelho, como também há uma mensagem de erro. Quem acrescenta esta mensagem de erro? Pois um helper do que ainda não tínhamos falado: Html.ValidationMessageFor. Seu uso é como o dos helpers para gerar formulários: com uma expressão lambda indicamos a propriedade para a qual queremos mostrar suas mensagens de erro (se existirem). Esse é o código completo da visão que estamos usando:

@using (Html.BeginForm()) {
      @Html.ValidationSummary(true)
     <fieldset>
            <legend>DemoModel</legend>

            <div class="editor-label">
                  @Html.LabelFor(model => model.Nome)
            </div>
           <div class="editor-field">
                 @Html.EditorFor(model => model.Nome)
           @Html.ValidationMessageFor(model => model.Nome)
           </div>

            <div class="editor-label">
                  @Html.LabelFor(model => model.Idade)
            </div>
           <div class="editor-field">
                 @Html.EditorFor(model => model.Idade)
                  @Html.ValidationMessageFor(model => model.Idade)
            </div>

            <p>
                 <input type="submit" value="Create" />
           </p>
      </fieldset>
}

Outros atributos para validar

Há vários atributos para diferentes validações e todos são usados da mesma maneira: decorando as propriedades. Se sua aplicação exige que seus usuários tenham entre 18 e 65 anos, pode-se usar Range:

public class DemoModel
      {
           [Required]
           public string Nome { get; set; }
           [Range(18, 65)]
           public int Idade { get; set; }
     }

Mais atributos que existem:

  • StringLength: Para limitar o número de caracteres de um campo texto (p.ex. o password deve ter entre 6 e 15 caracteres).
  • Compare: Para que dois campos tenham o mesmo valor (p.ex. password e repetir password)
  • RegularExpression: Para validar contra uma expressão regular
É claro que existe a possibilidade de você criar seus próprios atributos para validações próprias mas isso é algo que deixamos para um artigo posterior!

Personalizar as validações

Se você vir a Figura 2 provavelmente se pergunte se é possível modificar a cor usada para mostrar os erros e a mensagem que se mostra. A resposta a ambas perguntas é sim. Para modificar a cor que se usa para mostrar os erros basta modificar a css. Os helpers usam a classe input-validation-error para indicar que o campo de formulário está mostrando um erro, assim que seu aspecto depende de como tenhamos definida essa classe na CSS. Por outro lado a mensagem que vemos é a que gera o framework por padrão, mas podemos modificá-la por uma nossa usando a propriedade ErrorMessage que tem todos os atributos de validação:

public class DemoModel
      {
           [Required(ErrorMessage = "Nada de anônimos. ¡Aqui todo mundo tem um nome!")]
           public string Nome { get; set; }
            [Range(18,65, ErrorMessage = "Só maiores de idade não aposentados")]
           public int Idade { get; set; }
     }

A Figura 3 mostra o resultado com essas mensagens de erro:


Figura 3: Erros com mensagens personalizadas

Sumário de validações falidas

Vimos como o helper Html.ValidationMessageFor nos permite mostrar as mensagens de erro vinculados a uma propriedade determinada. Porém, às vezes pode nos interessar mostrar um resumo com todas as mensagens de erro, algo como:


Figura 4: Sumário de validações falidas

Pois bem, como não podia ser de outro modo existe um helper específico para isso, chamado Html.ValidationSummary. Este helper pode gerar uma lista (<li>) de elementos não ordenados (<ul>) com todas as validações que tenham falhado. Seu uso é tão simples quanto acrescentar dito helper no lugar onde queiramos que apareça essa lista. Ademais admite vários parâmetros para personalizá-lo um dos quais permite acrescentar um título que se mostrará antes da lista:

@Html.ValidationSummary(true,"Há varios erros:")

A cadeia "Há varios erros:" será mostrada antes de mostrar a lista. O primeiro parâmetro, por sua parte, indica se a lista deve mostrar todos os erros (true) ou só aqueles que não estejam vinculados a nenhuma propriedade (false), ou seja, que sejam globais a todo o viewmodel (de verdade, é possível que haja erros no ModelState que não estejam associados a nenhuma propriedade em concreto).

Validação no cliente

Se usamos os atributos standard (não criamos atributos próprios) já temos a validação em cliente automática. Ou seja ao mesmo tempo que o usuário vá teclando os valores ou mude o foco já se irão mostrando os distintos erros que haja. Se há erros não poderá enviar o formulário. É claro que a validação em cliente não tem nada a ver com a segurança, é um tema de usabilidade (dar feedback ao usuário de forma mais rápida) assim que o uso de validação em cliente não impede de realizá-la em servidor. ASP.NET MVC a realiza sempre em servidor (e nós por nossa parte devemos comprovar sempre o valor da propriedade IsValid del ModelState).

Se por alguma razão se deseja desativar a validação em cliente em alguma visão, basta chamar o método Html.EnableClientValidation com o parâmetro a false:

@{ Html.EnableClientValidation(false); }
@using (Html.BeginForm())
      {
            // Codigo do form
     }

Se você cria atributos próprios para validações personalizadas então é sua responsabilidade certificar-se de que sejam compatíveis para validar em cliente (fique tranquilo, veremos em artigos posteriores como fazê-lo), mas os que vêm, o incluem de série.

Acrescentando erros próprios ao ModelState

Para terminar este artigo gostaria de mostrar como podemos acrescentar erros próprios no ModelState. Isto pode ser útil naqueles casos em que o código de validação não possa ser incorporado em um atributo (porque não dependa unicamente dos valores introduzidos pelo usuário mas que também dependa de fatores externos). O ModelState tem um método chamado AddModelError que serve exatamente para isto:

[HttpPost]
      public ActionResult Index(DemoModel data)
      {

            if (ModelState.IsValid)
            {
                  if (Manager.ExistePessoa(data))
                  {
                        ModelState.AddModelError("", "Ja existe uma pessoa com este nome");
                  }
            }

            if (!ModelState.IsValid)
           {
                  return View(data);
           }
            else
           {
                 // Codigo normal
                 return View("ok");
            }

}

Nesta ação, se não há erros no modelo (ou seja, os dados introduzidos pelo usuário são corretos) o controlador comprova se já existe uma pessoa com esses dados (usando uma classe inventada Manager), e se este for o caso acrescenta um erro no ModelState. Neste momento ModelState.IsValid deixa de ser true (posto que agora há um erro). ModelState.AddModelError tem dos parámetros:

  1. A que propriedade se atribui o erro. Se vale "" não se atribui a nenhuma propriedade (se entende que é um erro global que afeta todo o viewmodel).
  2. A mensagem de erro associado a dito erro.
Como podemos observar que exista o erro de "Já existe uma pessoa com este nome" é algo que depende dos dados introduzidos mas sobretudo do estado do sistema (que já exista ou não uma pessoa com este nome). Estes tipos de erros são os que costumam ser tratados usando AddModelError.

Bom, neste artigo introduzimos o modelo de validações de ASP.NET MVC. Vimos que é o ModelState, como usar DataAnnotations e como acrescentar nossos próprios erros no ModelState. Nos faltam vários aspectos que iremos tratando em artigos futuros como criar nossos próprios atributos de validação e ver outros mecanismos de validação que não seja usando atributos.






Usuários :    login / registro

Manuais relacionados
Categorias relacionadas
O autor

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