Atributos de validação personalizados no ASP.NET MVC 3

Blz, galera

Vimos no post anterior (aqui) como fazer validação de dados (client e server-side) no ASP.NET MVC 3.

Continuando no tema, hoje vou mostrar como é simples criar atributos de validação (Data Annotations) personalizados.

Ainda no exemplo dado no post anterior, citado acima, utilizei o atributo [RegularExpression] para validar o formato de e-mail da classe Pessoa. Imagine agora utilizar um atributo personalizado, como [EmailEmFormatoValido], no lugar do [RegularExpression]. Ficaria muito mais claro, além de encapsular a lógica de validação em um único lugar.

Para criar esse atributo personalizado é muito simples. Basta implementar uma classe que herde de ValidationAttribute (do namespace System.ComponentModel.DataAnnotations) e sobrescrever o método IsValid da mesma. Fica assim:

public class EmailEmFormatoValido : ValidationAttribute
{
    public EmailEmFormatoValido()
    {
        ErrorMessage = "E-mail deve estar em formato válido.";
    }

    public override bool IsValid(object value)
    {
        var email = value as string;
        if (email != null)
            return Regex.IsMatch(email, @"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*");
        return true;
    }
}

Simples não é? No construtor da classe, defini uma mensagem padrão e no método IsValid implementei a lógica de validação desejada.

Note que o método IsValid retorna “true” sempre que o valor do campo estiver nulo. Isso é recomendável, senão você estaria deixando a propriedade obrigatória mesmo que o atributo [Required] não estivesse sendo usado.

Agora que temos o atributo criado, vamos utilizá-lo na propriedade Email da nossa classe Pessoa, no lugar do atributo [RegularExpression]:

public class Pessoa
{
    [Required(ErrorMessage = "Nome deve ser preenchido")]
    public string Nome { get; set; }

    [Required(ErrorMessage = "E-mail deve ser preenchido")]
    [EmailEmFormatoValido]
    public string Email { get; set; }
}

Notem que usei o atributo [EmailEmFormatoValido] sem especificar a mensagem ErrorMessage, pois já defini uma mensagem padrão no construtor da classe como mostrado anteriormente. No entanto, você pode especificá-la, sobrescrevendo a mensagem padrão.

Isso é tudo que precisamos para termos uma validação server-side usando nosso atributo personalizado. No entanto, caso você rode a aplicação, notará que a validação client-side não funciona. Isto ocorre porque os scripts client-side são gerados somente para os atributos básicos [Required], [RegularExpression], [Range] e [StringLength].

Sendo assim, é preciso implementar a validação client-side para seu atributo personalizado.

O primeiro passo é implementar um ModelValidator associado ao nosso atributo EmailEmFormatoValido. Fazemos isso, herdando de DataAnnotationsModelValidator<T> (do namespace System.Web.Mvc), onde T é nosso atributo:

public class EmailValidator : DataAnnotationsModelValidator<EmailEmFormatoValido>
{
    private readonly string _mensagem;

    public EmailValidator(ModelMetadata metadata, ControllerContext context, EmailEmFormatoValido attribute)
        : base(metadata, context, attribute)
    {
        _mensagem = attribute.ErrorMessage;
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = _mensagem,
            ValidationType = "email"
        };
        return new[] { rule };
    }
}

Notem que precisamos sobrescrever o método GetClientValidationRules, o qual retorna um array de regras que servirão como metadata para a validação em javascript que iremos escrever.

No exemplo acima, estou retornando apenas uma regra (ModelClientValidationRule) com a mensagem de erro igual à mensagem de erro definida em nosso atributo EmailEmFormatoValido (a mensagem de erro é obtida de attribute.ErrorMessage no construtor da classe). Definimos também na regra, o ValidationType para “email”, que mais tarde usaremos em nosso javascript.

O segundo passo é registrar esse novo validator, vinculando-o ao atributo EmailEmFormatoValido. Fazemos isso em Application_Start, no Global.asax:

protected void Application_Start()
{
    // mantenha o codigo existente como está

    // vinculando nosso novo validator ao nosso atributo
    DataAnnotationsModelValidatorProvider.
        RegisterAdapter(typeof(EmailEmFormatoValido), typeof(EmailValidator));
}

Por fim, precisamos implementar a validação em javascript:

<script type="text/javascript">
Sys.Mvc.ValidatorRegistry.validators.email = function (rule) {
    return function (value, context)
    {
        if (!value || EhEmail(value)) return true;
        return rule.ErrorMessage;
    };
};

function EhEmail(email)
{
    regex = new RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?");
    return regex.test(email);
}
</script>

O mais importante do código acima está em “….ValidatorRegistry.validators.email“. Ele está adicionando um validator ao dicionário de validators, usando a chave “email”, que deve ser o mesmo nome que definimos no ValidationType da classe EmailValidator.

Ufa! Terminamos! Após criar nosso validator EmailValidator (1), registrá-lo no Global.asax (2) e implementar a validação javascript (3), podemos ver a nosso atributo EmailEmFormatoValido funcionando corretamente no lado cliente.

Claro, vale lembrar que sua view (ou master) deve referenciar os seguintes scripts (juntamente com o script de validação mostrado acima):

<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

Com isso, vimos como é fácil customizar os Data Annotations, podendo criar validadores para formato de e-mail, validadores de CPF/CNPJ e mais uma infinidade, deixando nossa validação simples e padronizada.

Obs.: tudo que foi mostrado aqui pode ser utilizado no ASP.NET MVC 2.

Críticas e sugestões, comentem!

[]s e até a próxima!

Anúncios

17 comentários em “Atributos de validação personalizados no ASP.NET MVC 3

  1. Robson!
    Por acaso se tem algum artigo sobre MVC para que eu possa colocar na minha monografia!
    Tipo
    O que e MVC?
    Como Funciona?

    É que preciso de referencia bibliografica, AUTOR, ANO, PAGINA E NOME DO LIVRO OU ARTIGO, REVISTA.

    Se tiver e se puder me passar!
    Fico muito agradecido

    1. Assim de cabeça não sei de nenhum.. Você vai encontrar nos livros de padrões de projeto (GoF e Head First). Isso se você estiver se referindo ao MVC “puro” e não especificamente ao ASP.NET MVC.
      []s

  2. Robson, Quando insiro o codigo javascript mostrado obtenho o seguinte erro:
    “Uncaught ReferenceError: Sys is not defined” Sabe me dizer o porque ?

    Obs.: Entendo que ele esta me dizendo que a referência ou objeto “Sys” não existe.

    1. Olá, Fagner
      Desculpe pela demora.
      No exemplo usei o validator client-side da própria Microsoft (note a linha ‘Sys.Mvc.ValidatorRegistry.validators…’) ao invés de faze-lo com JQuery. Isso acabou não ficando claro no post. Portanto, você precisará incluir mais um js, se não me engano o nome é: MicrosoftMvcValidation.js.

      NO ENTANTO, os scripts Microsoft****.js estão obsoletos, tendo sido substituídos pelos equivalentes em JQuery. Portanto, recomendo não mais utilizá-los. Espero em breve atualizar este post (ou escrever outro) mostrando como adicionar um custom validator client-side usando a validação do JQuery.

      Em uma breve “googlada”, você encontra artigos legais. A ideia é a mesma mostrada aqui.
      []s

  3. Gostaria de saber se você já fez ou tem algum exemplo para validação de enumeradores?
    Parabéns pelo Post e pelo seu trabalho!!!
    Abraço
    att

Participe! Vamos trocar uma ideia sobre desenvolvimento de software!

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s