Hackeando los validadores de ASP.NET

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Hackeando-los-validadores-de-ASPNET.aspx

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

Sin categoría

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *