JASoft.org

El blog de José Manuel Alarcón Aguín. Programación web y mucho más...

MENÚ - JASoft: JM Alarcón

Hackeando los validadores de ASP.NET

ASP.NET Web Forms ofrece unos maravillosos controles de validación que nos permiten controlar los valores de los campos de un formulario tanto en el navegador como luego en el servidor. Así, basta con arrastrar unos cuantos controles sobre la página para validar campos obligatorios, rangos de valores, expresiones regulares, tipos de datos introducidos, etc... Incluso podemos definir nuestras validaciones personalizadas, si bien esto requiere mucho más esfuerzo por nuestra parte.

Estos controles están muy bien pero, en el lado de cliente (navegador), se limitan a mostrar mensajes cuando falla alguna validación:

Validadores_Normales

Los mensajes podemos agruparlos en un control de resumen y cambiar el estilo que utilizan, pero no nos permiten apenas configuración del lado cliente.

¿Qué pasa si lo que necesitamos es tener mayor control sobre lo que ocurre en el navegador durante la validación? ¿Podemos hacer algo sin complicarnos demasiado la vida?

Por ejemplo, un caso muy típico es querer destacar los campos incorrectos marcándolos con otro color, dejándolos nuevamente en su estado normal si el error se subsana:

Validadores_Sobrescritos

En el ejemplo de la figura lo que hacemos es poner de color rojo (aplicar un estilo “error”) a los campos de texto cuando hay algún problema de validación.

Obviamente esto se puede conseguir mediante jQuery o directamente haciendo la validación con JavaScript, pero la idea es conseguirlo aprovechando la potencia de los controles de validación de ASP.NET. Es decir, lo que queremos conseguir es sumar funcionalidad a la que traen ya por defecto los controles de validación de ASP.NET.

La API de lado cliente

Aunque es muy poco conocida y no está documentada, los validadores de ASP.NET ofrecen una API de lado cliente a la que es fácil sacarle partido. Basta hacer un poco de ingeniería inversa sobre el JavaScript que tiene para ver que es fácil “hackearlos” para tener un control absoluto sobre cómo trabajan.

La primera cuestión interesante a tener en cuenta es que, al agregar cualquier validador a una página, en ésta se define una colección JavaScript llamada Page_Validators que contiene referencia a objetos de tipo Validator que representan la funcionalidad de lado cliente de cada uno de los validadores que hay en la página.

Estos validadores poseen algunas propiedades interesantes, que son las que nos permitirán controlar su funcionalidad:

  • controltovalidate: contiene una referencia al control al cual valida el validador actual: el cuadro de texto o lo que sea.
  • evaluationfunction: una referencia a la función JavaScript que realiza la validación del control. A esta se le pasa como argumento el valor contenido actualmente en el control.
  • initialvalue: el valor inicial contenido en el control. Se utiliza para comparar con el valor actual y saber si éste ha cambiado o no.
  • isvalid: identifica si el control que se valida, tras haber efectuado la validación, está en un estado válido o no.
  • uniqueID: el identificador único del control de validación.

Con estos elementos ya tenemos todo lo necesario para poder controlar a voluntad la validación reutilizando todo lo que hacen los controles de validación originales.

En concreto lo que debemos hacer es subclasificar el comportamiento de validación de cada control en el que estemos interesados para poder hacer uso de la funcionalidad original pero además añadirle la nuestra propia.

En el ejemplo expuesto de cambiar el estilo de los controles no válidos (descargar aquí, 2 KB) este es el código que he utilizado:

   1: <script type="text/javascript">
   2:     var tmrReady = setInterval(isPageFullyLoaded, 100);
   3:     function isPageFullyLoaded() {
   4:         if (document.readyState == "loaded" || document.readyState == "complete") {
   5:             onPageReady();
   6:             clearInterval(tmrReady);
   7:         }
   8:     }
   9:  
  10:     //Aquí la página está lista y subclasifico el evento de validación
  11:     //para recorrer los validadores y comprobarlos
  12:     function onPageReady() {
  13:         for (i = 0; i < Page_Validators.length; i++) {
  14:             overrideValidation(Page_Validators[i]);
  15:         };
  16:     }
  17:  
  18:     //Subclasifico el método de validación de cada validador
  19:     function overrideValidation(validator) {
  20:         var prevEvalFunc = validator.evaluationfunction;
  21:         validator.evaluationfunction = function (val) {
  22:             //llamo al validador anterior
  23:             var valido = prevEvalFunc(val);
  24:             //y ahora compruebo si es válido el campo o no
  25:             if (valido) {
  26:                 //Si no es válido marco el control con otro estilo
  27:                 document.getElementById(val.controltovalidate).className = "noerror";
  28:             }
  29:             else {
  30:                 document.getElementById(val.controltovalidate).className = "error";
  31:             }
  32:             return valido;
  33:         };
  34:     }
  35:  
  36: </script>

El bloque del principio es simplemente una forma manual de detectar que el documento está listo e inicializarlo. Lo he explicado anteriormente en este blog ya, y es equivalente a utilizar $() de jQuery sin necesidad de tener jQuery a mano.

Cuando la página está lista se llama al método onPageReady(). Éste lo que hace es recorrer todos los validadores definidos en la página (usando la colección Page_Validators) y llamar, para cada uno de ellos, a la función que he llamado overrideValidation, que se encarga de subclasificar la funcionalidad de validación y que es la verdadera función importante aquí.

Esta función lo que hace es, en primer lugar, obtener un “puntero” (una referencia) a la función de validación del validador (línea 20) usando su propiedad evaluationfunction. Así, en la variable preEvalFunc tenemos una referencia a esta función y podemos llamarla cuando queramos. Es como tener un alias para llamar a la función original.

Ahora lo que tenemos que hacer es sustituirla por una función propia con la funcionalidad que queramos añadir. Y es eso precisamente lo que hacemos a partir de la línea 21. Se asigna a evaluationfunction una nueva función anónima que toma como parámetro el valor del control a validar (como la función original). Esta función será llamada automáticamente por el framework de validación cuando haya algo que validar (como se hace con la función habitual que vamos hemos sustituido). Lo que hará esta nueva función de validación cuando sea llamada es lo siguiente:

  1. Llama a la función de validación anterior: Recordemos que no queríamos anular su funcionalidad sino ampliarla, así que lo que hacemos es simplemente sacarle partido a lo ya existente (línea 23). Esta función devuelve un booleano indicando si ha tenido éxito (en caso de validación correcta) o no. Esto es otro ejemplo más de la interesante capacidad que nos ofrece JavaScript de trabajar con referencias a funciones.
  2. Definimos nuestra funcionalidad personalizada: en este caso nos limitamos a cambiar la clase CSS del campo a validar en función de si es correcto o no. En un caso general podríamos hacer lo que nos viniera en gana, con funcionalidades mucho más complejas como por ejemplo mostrar el mensaje de error en un globo o una capa usando jQuery o cualquier cosa que se nos ocurra. A efectos de demostración es suficiente con lo que se muestra entre las líneas 25 a 31.
  3. Devolvemos el resultado de la validación: es necesario indicar siempre el resultado de la validación para que la infraestructura lo reconozca y actúe en consecuencia. En este caso devolvemos el verdadero valor porque queremos mostrar u ocultar las etiquetas del validador de ASP.NET, pero si quisiésemos que nunca se mostraran ya que hemos dado el feedback de otra forma podríamos engañar a la infraestructura de validación devolviendo siempre un true como resultado de la función. El verdadero resultado siempre lo conoceríamos gracias a la funcionalidad original a la que llamamos internamente.

¡Listo! Con esto podemos controlar a voluntad el proceso de validación de lado cliente y además vemos algunas técnicas interesantes de JavaScript.

Sobre todo esto no hay documentación por ahí (o al menos yo no la he encontrado) y sale del análisis que he hecho sobre el funcionamiento de estos controles, así que ¡espero que te sea útil!

¿Te ha gustado este post? - Aprende .NET con los cursos on-line tutelados de campusMVP:
   ·
Preparación del examen 70-515: Desarrollo Web con .NET 4.0 (Tutelado por mi)
   · Desarrollo Web con ASP.NET 4.0 Web Forms (Tutelado por mi)
   · ASP.NET 4.0 Web Forms desde cero (Tutelado por mi)
   · Desarrollo Web con ASP.NET MVC 3  
   · jQuery paso a paso para programadores ASP.NET

José Manuel Alarcón José Manuel Alarcón
Fundador y director de campusMVP.es, el proyecto de referencia en formación on-line para programadores en lengua española. Autor de varios libros y cientos de artículos. Galardonado como MVP de Microsoft desde 2004. Gallego de Vigo, amante de la ciencia y la tecnología, la música y la lectura. Ayudando a la gente en Internet desde 1996.
Descarga GRATIS mi último libro (no técnico): "Tres Monos, Diez Minutos".
Banner

Comentarios (6) -

hola JM Alarcón.. un saludo..

buscando información sobre javascript llegue hasta aquí, la cuestión es que ya llevo varias semanas buscando algún ejemplo ya sea en javascrip o jquery (que para el problema cualquiera sirve según como e leído) de como puedo mostrar los archivos y carpetas de mi pc (ojo no la del servidor en el cual esta alojada la web) en un treeview por ejemplo.
¿para que esto?
para subir a mi servidor cualquier tipo de archivo..
como?
pues un ejemplo seria el filezilla.. osea en el treeview donde están los datos de mi pc arrastrar un archivo hasta una ubicación en la web donde al soltarlo empiece el proceso de carga al servidor..

ya me e paseado por todos lados tratando de encontrar un ejemplo que me oriente pero nada lo único que hay son demos, los cuales no permiten explorar el código para su entendimiento

como nota adicional estoy utilizando visual estudio 2010 con lenguaje C# y web form..

de antemano te agradezco tu atención y ojala me puedas orientar.. se be que es un buen blog....

Responder

Spain José Manuel Alarcón

Hola Jesús,

Eso no se puede hacer desde un navegador a menos que utilices una extensión creada en Java o algo similar. Los navegadores protegen al usuario de posibles virus y demás código malicioso ejecutándose en un entorno limitado por lo que no se pueden conseguir nativamente muchas de las cosas que en otro tipo de aplicaciones sí es posible.

Saludos,

JM

Responder

Mexico Antonio de Jesus

Hola, que tal! me ha gustado mucho el post y me ha servido de mucho, pero tengo el siguiente problema:
supongamos que tengo un formulario con 3 textbox cada uno con su respectivo validador y un boton "Enviar", ya sabemos que cuando se clickamos el boton "Enviar" los validadores hacen su trabajo y si algun textbox falla simplemente el postback no se hace y se muestran los mensaje de los validadores de dichos campos fallidos, pero quisiera dar una funcionalidad extra, por ejemplo que al dar click en el boton se comprueben si hay validadores mostrados (campos no validos) y darle el foco al primer campo fallido.

En otras palabras, como podria ejecutar codigo javascript/jquery cuando cualquier validador es mostrado, es decir cuando cualquier campo, ya sea uno o mas fallen.

Regularmente cuando un formulario NO es valido solamente los mensajes de error (validadores) se muestran, pero seria muy bueno hacer un scrollTo hacia el primer campo erroneo, esto cuando un formulario es grande.

Saludos!

Responder

Spain José Manuel Alarcón

Hola,

Eso está en ASP.NET Web Forms desde la versión 1.0: simplemente establece la propiedad SetFocusOnError de todos los validadores a "true" y ya tendrás justo lo que estás buscando.

Saludos.

Responder

Mexico jose ignacio lopez

Hola jose manuel:

mi pregunta es con un error que me tira tu codigo en la parte de:

       //Subclasifico el método de validación de cada validador
       function overrideValidation(validator) {
           var prevEvalFunc = validator.evaluationfunction;
           validator.evaluationfunction = function (val) {
               //llamo al validador anterior
               var valido = prevEvalFunc(val);
               //y ahora compruebo si es válido el campo o no
               if (valido) {
                   //Si no es válido marco el control con otro estilo
                   document.getElementById(val.controltovalidate).className = "noerror";
               }
               else {
                   document.getElementById(val.controltovalidate).className = "error";
               }
               return valido;
           };
       }

cuando comparas  var valido = prevEvalFunc(val); el valor "val" no veo que lo declares en ninguna parte y por defecto no se que valor espera prevEvalFunc. Me podrias ayudar con esto Gracias y Saludos.

Responder

Spain José Manuel Alarcón

¿Cómo que no lo declaro? Es el parámetro que se pasa a la función asignada como nuevo evaluador. Te recomiendo que repases el concepto de "closure" en JavaScript. He escrito un post sobre ello:

www.jasoft.org/.../...-9579-41bd-9e2c-36569dc.aspx

Y en mi libro de JavaScript se trata este tema (y muchos otros) a fondo:

www.campusmvp.es/.../...e%C3%B1adores-web_159.aspx

JavaScript es un lenguaje muy incomprendido...

Saludos.

Responder

Agregar comentario