Atributo para validar Números utilizando Data Annotation em Asp.Net MVC 4 com C# (CSharp)

NumeroBrasil, atributo customizado para validar Números em Asp.Net MVC 4 com C#(CSharp) e integração em javascript para o lado do cliente.


Autor : Antonio Carlos Ferreira de Azevedo
Postado em : 18/04/2016

Data Annotation Custumizado [NumeroBrasil()]

Nesta postagem você vai aprender a validar um campo Int ou Double usando Data Annotation e jquery.validate onde será feita a validação tanto do lado do cliente como no servidor.
Vamos criar aqui uma classe derivada da ValidationAttribute e criar nossa classe customizada para a validação no servidor.

NumeroBrasilAttribute

ErrorMessage Mensagem padrão de erro.
DecimalRequerido True Se o pondo decimal for requerido False se o ponto decimal não for requerido.
PontoMilharPermitido True se o ponto milhar for permitido False se o ponto milhar não for permitido.

Obs:Não utilizar o ponto milhar quando for tratar diretamente o campo int, double e decimal em sua validação padrão este despreza o valor por não reconhecer o ponto milhar, caso queira utilizar mascaras você pode faze-lo de duas maneiras :

1) Utilize um campo string e converta quando for gravar no banco de dados.
2) Ou veja nossa postagem sobre ModelBinder - Customizando o vinculo do Modelo com o HTML AspNet com C# (CSharp)

Crie uma classe na pasta Models em seu projeto MVC com o nome de NumeroBrasilAttribute.cs copie e cole o código abaixo.

NumeroBrasilAttribute.cs

/* 
 * Atributo NumeroBrasil
 * 
 * Data Annotations para Validar um int ou double.
 * 
 * Visite nossa página http://www.codigoexpresso.com.br
 * 
 * by Antonio Azevedo
 *  
 * Chamada em sua Classe : 
 *   [NumeroBrasil(ErrorMessage="Sua mensagem de erro", DecimalRequerido=true/false, PontoMilharPermitido=true/false)]
 *    
 */
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

public class NumeroBrasilAttribute : ValidationAttribute, IClientValidatable
{
    public Boolean DecimalRequerido { get; set; }
    public Boolean PontoMilharPermitido { get; set; }
    public NumeroBrasilAttribute()
    {
        this.ErrorMessage = "Valor inválido.";
        this.DecimalRequerido = false;
        this.PontoMilharPermitido = false;
    }

    protected override ValidationResult IsValid(
        object value,
        ValidationContext validationContext)
    {

        // Verifica se o Valor é nulo
        if (value == null)
        {
            value = "";
        }

        string newValue = value.ToString();

        // Verifica se Ponto milhar é permitido, se sim retira os pontos para validação
        if (PontoMilharPermitido)
        {
            newValue = newValue.Replace(".", string.Empty);
        }
       
        // Caso o valor informado seja nulo não é requerido retorna sem validar
        if (value.ToString() == "" && DecimalRequerido == false)
        {
            return ValidationResult.Success; ;
        }

        // Verifica se decimal é requerida para fazer a validacao como double ou com integer
        // Se a conversão não for possivel retor com erro padrão
        if (DecimalRequerido==true)
        {
            try
            {
                double x = Convert.ToDouble(newValue);
            }
            catch
            {
                return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
            }
        }
        else
        {
            try
            {
                Int32 x = Convert.ToInt32(newValue);
            }
            catch
            {
                return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
            }
        }

        // Retorna com sucesso caso a converão tenha sido feita
        return ValidationResult.Success;
    }

    // Diretivas para validação do lado do Cliente, implementa com jquery.validate
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
        ModelMetadata metadata,
        ControllerContext context)
    {
        var Rule = new ModelClientValidationRule
        {
            ValidationType = "numerobrasil",
            ErrorMessage = this.FormatErrorMessage(metadata.PropertyName)

        };

        string[] array = new string[] {DecimalRequerido.ToString(),PontoMilharPermitido.ToString()};
      
        Rule.ValidationParameters["params"] = string.Join(",", Array.ConvertAll(array, x => x.ToString()));
    
        yield return Rule;
    }
}

Agora vamos cuidar da validação do lado no cliente, ou seja, no navegado do cliente.
O MVC se encarrega de transportar os parametros para nosso HTML mas mesmo assim temos que fazer toda a validação em JavaScript novamente.

Crie uma arquivo JavaScript na pasta Scripts de seu projeto MVC, de o nome de CustomValidacoes.js copie e cole o código abaixo.

CustomValidacoes.js

// Adicionamos o método ranger para sobrepor o método original e corrigir os valores passados,
// retirando o ponto milhar e trocando a virgula decimal por ponto decimal, 
// Com isto solucionamos os conflitos ao tentar definir um range para um valor quando utilizamos o atributo NumeroBrasil 
$.validator.addMethod('range',
   function (value, element, params) {
    
    // Coleta os parametros passados, valor maximo e minimo
    var min = params[0];
    var max = params[1];

    // Retira todo ponto de milhar formatado no campo valor
    var pos = value.indexOf('.');
    while (pos > -1) {
        value = value.replace('.', '');
        pos = value.indexOf('.');
    }

    // Troca virgula decimal por ponto decimal
    value = value.replace(',', '.');

    // Faz a validacao do valor, comparando com o valor minimo e maximo
    if (value < min)
    {
        return false;
    }

    if (value > max) {
        return false;
    }

    return true;
});


// Adicionamos o metodo number para sobrepor o metodo padrão e atribuindo sempre um retorno verdadeiro para garantir 
// que o JQuery não vai tratar os numeros exibindo mensagens indesejadas. 
$.validator.addMethod('number',
   function (value, element) {
        return true;
});

// Aqui adicionamos os metodos respeitando os nomes gerado em nossa classe atributo
// os nomes devem estar em caixa baixa tanto na integração como aqui no JavaScript (Nome atributo, parametro)
$.validator.unobtrusive.adapters.addSingleVal('numerobrasil', 'params');

//Aqui temos a funcao que Valida do lado do cliente os números digitados utilizando uma expressão regular
$.validator.addMethod('numerobrasil',
function (value, element, params) {

    // Separamos o parametros recebidos
    var parametros = params.split(',');

    // Verifica o Ponto de milhar
    if (parametros[1].toString() == "True") {
        var pos = value.indexOf('.');
        while (pos > -1) {
            value = value.replace('.', '');
            pos = value.indexOf('.');
        }
    }

    // Valida caso o valor não tenha sido preenchido
    if (value.length == 0) {
        return true;
    }

    var expReg = '';

    // atribui a expressao regular com ou sem ponto decimal
    if (parametros[0].toString() == 'False') {
        expReg = /^[-+]?\d*$/;
    }
    else {
        expReg = /^[-+]?\d*\,?\d*$/;
    }

    // Valida a expressão, se for compativel vai retornar validando a campo, caso contrario exibe a mensagem de erro informada no atributo;
    return value.match(expReg);
});

Este arquivo deve ser carregado após o carregamento do jquery.validate, estamos sobrepondo o método number do JQuery.validate para evitar que seja feita a validação padrão.

Exemplo de como utilizar o atributo em sua classe.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using SeuProjeto.Models;

namespace AspNetMVC_Aula.Models
{
    public class ModAluno
    {
       [NumeroBrasil(ErrorMessage = "Número inválido", DecimalRequerido = true, PontoMilharPermitido = false )]
       public double? Valor { get; set; }
    }
}





Comentários

Thomaz em 23/05/2016 17:38:17
 

Quando uso seu componente para validar números não estou conseguindo usar o atributo range, só esta validando corretamente o valor minimo, o valor máximo esta dando problema. testei aqui e se não usar seu componente funciona perfeitamente.


Antonio Azevedo (Administrador) em 27/05/2016 01:14:58
 

Colega, desculpe ai, realmente fiz alguns testes aqui e o problema era na realidade a formatação, customizei a range do JQuery e agora estamos retirando os pontos de milhar e trocando a virgula decimal por ponto decimal. Testei aqui e agora esta tudo funcionando, verifique no código Java Script e adicione o método
$.validator.addMethod('range'
Que adicionei no código.


Thomaz em 27/05/2016 09:45:23
 

Agora funcionou, valeu.