Asp.Net Validator Assíncrono    

Neste post passado falei como usar Validator com controles HTMLs puros, para facilitar algumas coisas quando se usa Ajax.

Hoje vou falar novamente sobre Validators, mas agora criando um customizado para necessidades que muitas vezes podemos achar no desenvolvimento de sites com Ajax: Validações Assíncronas.

Imagine um formulário de cadastro, totalmente com Ajax, e você gostaria de validar informações de negócio, onde muitas vezes é necessário fazer algum tipo de consulta em banco de dados, etc.

Vamos supor: Você quer saber, num formulário de cadastro de usuário, se o usuário digitado já existe na base de dados, e mostrar o erro no momento que o usuário digitar o usuário e trocar o foco do controle. Veja bem, eu sei que é possível fazer isso com simples Ajax e os eventos onblur do JavaScript, mas a idéia deste post é mostrar como criar novos controles Asp.Net Validator, e aproveitar funcionalidades como o Validator Callout.

Como funciona um Validator?

No post citado acima, expliquei rapidamente como funciona um Validator, agora vou explicar um pouco mais.

Todo Validator herda da classe System.Web.UI.WebControls.BaseValidator, nessa classe existe um método chamado AddAttributesToRender, o qual é responsável por renderizar os atributes que os códigos do lado do cliente usarão para validar as informações de um campo. Sempre que um Validator é implementado, é necessário renderizar atributos específicos de acordo com a função do Validator.

Estes atributos são necessários porque os Validator precisam renderizar as propriedades definidas no Server Side para o navegador do Cliente. Em geral, os Validators realizam suas validações ainda no JavaScript, por isso, o JavaScript precisa conhecer os controles que serão validados, as mensagens de erros, etc. Para isso, o Asp.Net utiliza o método RegisterExpandoAttribute , que pode ser encontrado tanto Page.ClientScript como no ScriptManager. No nosso caso, como estaremos usando este validators sempre com Ajax, vamos utilizar o método RegisterExpandoAttribute do ScriptManager.

Obs.: Para ficar mais correto, poderíamos utilizar um Padrão de Projeto conhecido como Adapter, onde ficaria encapsulado a utilização do método RegisterExpandoAttribute do Page.ClientScript ou do ScritptManager de forma transparente, mas isso vai além do intuito deste post, e para ficar mais simples, estou utilizando diretamente o do ScriptManeger.

E para que serve o método RegisterExpandoAttribute? Este método renderiza propriedades em objetos JavaScripts. Se for ver como o Validator do post anterior foi renderizado, veremos:

var MainContent_reqNome = document.all ? document.all["MainContent_reqNome"] : document.getElementById("MainContent_reqNome");
MainContent_reqNome.controltovalidate = "MainContent_txtNome";
MainContent_reqNome.errormessage = "Preencha o Nome";
MainContent_reqNome.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
MainContent_reqNome.initialvalue = "";

No exemplo acima, MainContent_reqNome é objeto JavaScript que representa o Validator, e controltovalidate, errormessage, evaluationfunction e initialvalue são os ExpandoAttribute.

Criando o AsyncValidator

Para criar Validator Assíncrono, iremos definir duas propriedades no lado do servidor para conseguirmos informações básicas do que o Usuário quer validar. A maioria das demais propriedades de um validator, como ControlToValidate, já estão implementadas na classe base BaseValidator.

	/// 
        /// Método estático na página que fará a validação.
        /// Este método deve estar decorado com o atributo WebMethod
        /// Sua assinatura deve ser:
        /// 
        /// public static bool NomeDoMetodo(string valor){}
        /// 
        /// 
        public string ServerValidationMethod
        {
            get
            {
                if (this.ViewState["ServerValidationMethod"] == null)
                    return "";

                return this.ViewState["ServerValidationMethod"].ToString();
            }
            set { this.ViewState["ServerValidationMethod"] = value; }
        }

        /// 
        /// Caso se deseje alterar o valor do campo definido na propriedade ControlToValidate, define-se um método no javascript com a seguinte assinatura function (sender,args).
        /// O parâmetro args contém a propriedade Value, que contem o valor do campo, que pode ser alterado.
        /// Neste caso, o valor assumido para ser enviado para o server é o valor alterado.
        /// 
        public string CustomValueFunction
        {
            get
            {
                if (this.ViewState["CustomValueFunction"] == null)
                    return "";

                return this.ViewState["CustomValueFunction"].ToString();
            }
            set { this.ViewState["CustomValueFunction"] = value; }
        }

 

O código acima define duas propriedades. Acredito que a propriedade que merece um comentário extra é a ServerValidationMethod. Essa propriedade armazena o nome de um PageMethod que é o responsável por fazer a validação no lado do Server. Por padrão ele recebe a informação que está no campo a ser validado, porém, essa informação pode ser alterada antes de ser enviada ao servidor, pelo método JavaScript definido na propriedade CustomValueFunction.

Para fazer estas informações definidas no servidor ficarem disponíveis no cliente, sobrescrevemos o método citado acima (AddAttributesToRender), e renderizamos as duas proriedades e algumas outras:

protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            
            base.AddAttributesToRender(writer);
            ScriptManager.RegisterExpandoAttribute(this, this.ClientID, "evaluationfunction", "AsyncValidatorEvaluateIsValid", false);
            ScriptManager.RegisterExpandoAttribute(this, this.ClientID, "isvalidating", "0", false);
            ScriptManager.RegisterExpandoAttribute(this, this.ClientID, "myclientid", this.ClientID, false);
            ScriptManager.RegisterExpandoAttribute(this, this.ClientID, "resultado", "true", false);
            ScriptManager.RegisterExpandoAttribute(this, this.ClientID, "servervalidationmethod", ServerValidationMethod, false);
            ScriptManager.RegisterExpandoAttribute(this, this.ClientID, "customvaluefunction", CustomValueFunction, false);
            ScriptManager.RegisterExpandoAttribute(this, this.ClientID, "ultimovalor", "", false);
            
        }

A maioria dos atributos renderizados são de uso do JavaScript que utilizaremos para fazer a validação, mostrado abaixo. Apenas um merece uma especial atenção: evaluationfunction.

O atributo evaluationfunction é necessário para todos os Validators do Asp.Net WebForm, este atributo armazena o nome do método JavaScript que realiza a validação no lado do cliente. Os scripts ClientSide do WebForm chamam sempre o método definido neste atributo ao executar a validação ao clicar em um botão de submit.. Em um RequiredFieldValidator por exemplo, este atributo contém o nome do método RequiredFieldValidatorEvaluateIsValid, este é o método que verifica se um controle é preenchido ou não.

No nosso caso, como o exemplo mostra, o nosso método responsável por validar o campo, ou seja, chamar o PageMethod criado pelo usuário do Validator responsável pela validação de fato será o AsyncValidatorEvaluateIsValid.

Nosso código JavaScript deve ficar da seguinte forma:

 function AsyncValidatorEvaluateIsValid(val,resultado,userContext,methodName) {
    
    var value = ValidatorGetValue(val.controltovalidate);
    
    //Possíveis valores para isvalidating:
    //0 : Não está validando e deve ir ao server fazer a validação
    //1 : Está na validação, esperando resposta do server, não deve ser executado nada
    //2 : Retornou da validação, deve ser retornado o valor armazenado no retorno
    
    if(val.isvalidating==1){
        return true;
    }
    
    if(val.isvalidating==2){
        val.isvalidating=0;
        return val.resultado; 
    }
    
      
    if(val.customvaluefunction.length>0){
        var args = { Value:value};  
        eval(val.customvaluefunction + "(val, args);");
        value = args.Value;
    }
       

    if(val.servervalidationmethod.length==0) return true;

    val.isvalidating = 1;
    
    eval('PageMethods.'+val.servervalidationmethod+'(value,function (valorRetorno,userContext,methodName){'+
    'val.resultado = valorRetorno;val.isvalid = valorRetorno;val.isvalidating = 2;val.evaluationfunction(val);'+
    '});');
       
     return true;
 
}

O código acima tem toda a lógica necessária para conseguir chamar o PageMethod definido na propriedade do Validator, aguardar o retorno, e informar se o validator foi válido ou não. A lógica não é das melhores, mas ajuda a exemplificar como deve funcionar um validator.

É importante informar que pelo fato de estarmos utilizando um PageMethod, precisamos adicionar um ScriptManager na página e habilitar a utilização de PageMethods, com a propriedade EnablePageMethods definida como true. Naturalmente, esta é só uma das formas de se validar informações assíncronas, foi a escolhida aqui por ser a mais simples.

Apenas com os códigos acima já podemos dizer que o Validator está pronto, mas você pode me perguntar: “Mas se eu quiser distribuir meu Validator, vou ter que distribuir um JavaScript junto?”. A resposta é :”Só se você quiser”.

Para quem não sabe, no .Net é possível colocar arquivos Embedded em DLLs. Para isso, basta colocarmos a propriedade Build Action do arquivo JavaScript como Embedded Resource, desta forma, ao compilar a DLL, o JavaScript será incluído dentro da DLL.

Para carregarmos este arquivo junto no momento do Load do Validator, apenas precisamos sobrescrever o método OnPreRender do Validator:

	protected override void OnPreRender(EventArgs e)
 {
    base.OnPreRender(e);
    ScriptManager.GetCurrent(this.Page).EnablePageMethods = true;
    Page.ClientScript.RegisterClientScriptResource(this.GetType(),
    "AssyncValidator.AsyncValidator.js");

 }

O uso do Validator é como o de qualquer outro, e pode ser usado com ValidatorCallout por exemplo.

Espero que este post possa ajudar você em validações com Web Forms e Ajax.

Até o próximo.

18. August 2010 00:50 by Frederico | Comments (1) | Permalink

Comments

Rafael
Ótimo post!
Isso, sem dúvida nenhuma, vai me ajudar muito.
Um grande abraço!
8/21/2010 6:47:14 AM #

Add comment




biuquote
  • Comment
  • Preview
Loading



Sobre mim

Minha Imagem

Meu nome é Frederico Batista Emídio, trabalho com desenvolvimento de sistemas profissionalmente a oito anos, porém, já faço sites pessoais a pelo menos dez anos.

Para saber mais clique aqui.

Páginas

Calendário

<<  November 2014  >>
MoTuWeThFrSaSu
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

Visualizar posts em um Calendário
Sigua @fredemidio

MCP Asp.NET