[ASP.NET] Validaciones no intrusivas en ASP.NET 4.5

Hola a todos, volviendo al desarrollo Web, hoy quiero aprovechar este post para mostrar una de las nuevas características de ASP.NET 4.5 que son las validaciones no intrusivas y el error que vamos a obtener cuando creamos una nueva aplicación Web.

Vamos a crear una nueva aplicación Web, agregar una nueva página aspx y allí vamos a tener un formulario para el registro de personas, adicionalmente usaremos algunos validadores que ofrece ASP.NET (si no los conoces revisa este post), entonces el sencillo código que necesitamos es:

   1:  <form id="form1" runat="server">
   2:  <div>
   3:      <table>
   4:          <tr>
   5:              <td>Nombre:</td>
   6:              <td>
   7:                  <asp:TextBox ID="txtNombre" runat="server" Width="300px"></asp:TextBox>
   8:                  <asp:RequiredFieldValidator ID="requiredNombre" runat="server" ControlToValidate="txtNombre" ErrorMessage="*"></asp:RequiredFieldValidator>
   9:              </td>
  10:          </tr>
  11:          <tr>
  12:              <td>Correo:</td>
  13:              <td>
  14:                  <asp:TextBox ID="txtCorreo" runat="server" Width="300px"></asp:TextBox>
  15:                  <asp:RequiredFieldValidator ID="requiredCorreo" runat="server" ControlToValidate="txtCorreo" ErrorMessage="*"></asp:RequiredFieldValidator>
  16:              </td>
  17:          </tr>
  18:          <tr>
  19:              <td>Usuario:</td>
  20:              <td>
  21:                  <asp:TextBox ID="txtUsuario" runat="server" Width="300px"></asp:TextBox>
  22:                  <asp:RequiredFieldValidator ID="requiredUsuario" runat="server" ControlToValidate="txtUsuario" ErrorMessage="*"></asp:RequiredFieldValidator>
  23:              </td>
  24:          </tr>
  25:          <tr>
  26:              <td>Clave:</td>
  27:              <td>
  28:                  <asp:TextBox ID="txtClave" runat="server" Width="300px" TextMode="Password"></asp:TextBox>
  29:                  <asp:RequiredFieldValidator ID="requiredClave" runat="server" ControlToValidate="txtClave" ErrorMessage="*"></asp:RequiredFieldValidator>
  30:              </td>
  31:          </tr>
  32:          <tr>
  33:              <td><asp:Button ID="btnGuardar" runat="server" Text="Guardar" /></td>
  34:          </tr>
  35:      </table>
  36:  </div>
  37:  </form>

Como vemos, el HTML es muy simple, peor ahora si lanzamos la aplicación vamos  a obtener el siguiente error:

error

Extraño no? simplemente creamos una página bastante sencilla (sin nada de código de servidor) y ya está fallando… pero si revisamos un poco el error vemos que dice “WebForms UnobtrusiveValidationMode requires a ScriptResourceMapping…” y ya tenemos una idea del error, lo que pasa es que con ASP.NET 4.5 tenemos una nueva característica la cual reducir la cantidad de código JavaScript necesario, la definición exacta dice:

You can now configure the built-in validator controls to use unobtrusive JavaScript for client-side validation logic. This significantly reduces the amount of JavaScript rendered inline in the page markup and reduces the overall page size.

Y dicha característica viene habilitada por defecto, para deshabilitarla vamos a nuestro Global.asax y en el evento Application_Start le decimos:

   1:  ValidationSettings.UnobtrusiveValidationMode = System.Web.UI.UnobtrusiveValidationMode.None;

Y ahora si lanzamos de nuevo la aplicación va a funcionar… pero no estaríamos aprovechando la validación no intrusiva, y si revisamos el HTML que es generado en el cliente tenemos:

   1:  <!DOCTYPE html>
   2:   
   3:  <html xmlns="http://www.w3.org/1999/xhtml">
   4:  <head><title>
   5:      Formulario
   6:  </title></head>
   7:  <body>
   8:      <form method="post" action="index.aspx" onsubmit="javascript:return WebForm_OnSubmit();" id="form1">
   9:  <div class="aspNetHidden">
  10:  <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
  11:  <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
  12:  <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="2pkd4JZKXmDyDJwu0HIaaT5x/EzINW3Fmj5ECNYtq721M2fzxgYIW/yLzuVDUpE6C5+JtdW4Mo7Mh7EH1jcQPCiVMtXSlRRYD3i7hJ3zQLM=" />
  13:  </div>
  14:   
  15:  <script type="text/javascript">
  16:  //<![CDATA[
  17:  var theForm = document.forms['form1'];
  18:  if (!theForm) {
  19:      theForm = document.form1;
  20:  }
  21:  function __doPostBack(eventTarget, eventArgument) {
  22:      if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
  23:          theForm.__EVENTTARGET.value = eventTarget;
  24:          theForm.__EVENTARGUMENT.value = eventArgument;
  25:          theForm.submit();
  26:      }
  27:  }
  28:  //]]>
  29:  </script>
  30:   
  31:   
  32:  <script src="/WebResource.axd?d=pynGkmcFUV13He1Qd6_TZAlhwiK26CMjFC_AwUoa5b3ERCspA6cmt_C-L8IOpCe633BVnc0wcDgTvonIIsSvwQ2&amp;t=634776373276709129" type="text/javascript"></script>
  33:   
  34:   
  35:  <script src="/WebResource.axd?d=x2nkrMJGXkMELz33nwnakEDhIJdn4zA9e1UqVq1SVvHhRhIprKEH70Wnr0YNmajC6LdVxQkRSvYza9nzCfZpzIEPGw7MYTdtpXpxdmoJjww1&amp;t=634776373276709129" type="text/javascript"></script>
  36:  <script type="text/javascript">
  37:  //<![CDATA[
  38:  function WebForm_OnSubmit() {
  39:  if (typeof(ValidatorOnSubmit) == "function" && ValidatorOnSubmit() == false) return false;
  40:  return true;
  41:  }
  42:  //]]>
  43:  </script>
  44:   
  45:  <div class="aspNetHidden">
  46:   
  47:      <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="bZYSXvfMEK7zHv9kV0tE+oZEnunr/8QE7gS9ULLQ4JyQa0/rv/1MRHr1bmVesMg6m/hAbEjp+lbFzmo0SV+QBKLDALpSfGJ0DfJ5FA03pkiwbqmguFNLc2gD7rvhbwgkveOk/e6MOPe2FJKM0lEwaBBiTadifQmqoEyokjWDmTbeUzilOBcBLxfc4JnhDC5gTorEWeVaxxVnfEZrKxCLsg==" />
  48:  </div>
  49:      <div>
  50:          <table>
  51:              <tr>
  52:                  <td>Nombre:</td>
  53:                  <td>
  54:                      <input name="txtNombre" type="text" id="txtNombre" style="width:300px;" />
  55:                      <span id="requiredNombre" style="visibility:hidden;">*</span>
  56:                  </td>
  57:              </tr>
  58:              <tr>
  59:                  <td>Correo:</td>
  60:                  <td>
  61:                      <input name="txtCorreo" type="text" id="txtCorreo" style="width:300px;" />
  62:                      <span id="requiredCorreo" style="visibility:hidden;">*</span>
  63:                  </td>
  64:              </tr>
  65:              <tr>
  66:                  <td>Usuario:</td>
  67:                  <td>
  68:                      <input name="txtUsuario" type="text" id="txtUsuario" style="width:300px;" />
  69:                      <span id="requiredUsuario" style="visibility:hidden;">*</span>
  70:                  </td>
  71:              </tr>
  72:              <tr>
  73:                  <td>Clave:</td>
  74:                  <td>
  75:                      <input name="txtClave" type="password" id="txtClave" style="width:300px;" />
  76:                      <span id="requiredClave" style="visibility:hidden;">*</span>
  77:                  </td>
  78:              </tr>
  79:              <tr>
  80:                  <td><input type="submit" name="btnGuardar" value="Guardar" onclick="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(&quot;btnGuardar&quot;, &quot;&quot;, true, &quot;&quot;, &quot;&quot;, false, false))" id="btnGuardar" /></td>
  81:              </tr>
  82:          </table>
  83:      </div>
  84:      
  85:  <script type="text/javascript">
  86:  //<![CDATA[
  87:  var Page_Validators =  new Array(document.getElementById("requiredNombre"), document.getElementById("requiredCorreo"), document.getElementById("requiredUsuario"), document.getElementById("requiredClave"));
  88:  //]]>
  89:  </script>
  90:   
  91:  <script type="text/javascript">
  92:  //<![CDATA[
  93:  var requiredNombre = document.all ? document.all["requiredNombre"] : document.getElementById("requiredNombre");
  94:  requiredNombre.controltovalidate = "txtNombre";
  95:  requiredNombre.errormessage = "*";
  96:  requiredNombre.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
  97:  requiredNombre.initialvalue = "";
  98:  var requiredCorreo = document.all ? document.all["requiredCorreo"] : document.getElementById("requiredCorreo");
  99:  requiredCorreo.controltovalidate = "txtCorreo";
 100:  requiredCorreo.errormessage = "*";
 101:  requiredCorreo.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
 102:  requiredCorreo.initialvalue = "";
 103:  var requiredUsuario = document.all ? document.all["requiredUsuario"] : document.getElementById("requiredUsuario");
 104:  requiredUsuario.controltovalidate = "txtUsuario";
 105:  requiredUsuario.errormessage = "*";
 106:  requiredUsuario.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
 107:  requiredUsuario.initialvalue = "";
 108:  var requiredClave = document.all ? document.all["requiredClave"] : document.getElementById("requiredClave");
 109:  requiredClave.controltovalidate = "txtClave";
 110:  requiredClave.errormessage = "*";
 111:  requiredClave.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
 112:  requiredClave.initialvalue = "";
 113:  //]]>
 114:  </script>
 115:   
 116:   
 117:  <script type="text/javascript">
 118:  //<![CDATA[
 119:   
 120:  var Page_ValidationActive = false;
 121:  if (typeof(ValidatorOnLoad) == "function") {
 122:      ValidatorOnLoad();
 123:  }
 124:   
 125:  function ValidatorOnSubmit() {
 126:      if (Page_ValidationActive) {
 127:          return ValidatorCommonOnSubmit();
 128:      }
 129:      else {
 130:          return true;
 131:      }
 132:  }
 133:          //]]>
 134:  </script>
 135:  </form>
 136:  </body>
 137:  </html>

Como vemos son 137 líneas de código y en la parte final bastante código JavaScript.

Ahora vamos a habilitar la validación no intrusiva (recuerden en el Global.asax):

   1:  ValidationSettings.UnobtrusiveValidationMode = System.Web.UI.UnobtrusiveValidationMode.WebForms;

Y para solucionar el error simplemente adicionamos la librería jQuery, pero lo debemos hacer de nuevo en el Global.asax de la siguiente manera:

   1:  ScriptManager.ScriptResourceMapping.AddDefinition("jquery",
   2:      new ScriptResourceDefinition
   3:      {
   4:          Path = "/Scripts/jquery-1.8.0.js"
   5:      }
   6:  );

En Path especificamos la ruta de la librería, y ahora si volvemos a lanzar la aplicación y a revisar el HTML generado tenemos:

   1:  <!DOCTYPE html>
   2:   
   3:  <html xmlns="http://www.w3.org/1999/xhtml">
   4:  <head><title>
   5:      Formulario
   6:  </title></head>
   7:  <body>
   8:      <form method="post" action="index.aspx" onsubmit="javascript:return WebForm_OnSubmit();" id="form1">
   9:  <div class="aspNetHidden">
  10:  <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
  11:  <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
  12:  <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="alparljtLhNy2xupYlZBZObSGVyvyxxogr8jThTTwWgWjbCJGZlWBvzpy1msUcxlr7zmHWThPw30eTwgrEBC9jxViHQKMQdl97MNwbdtIyg=" />
  13:  </div>
  14:   
  15:  <script type="text/javascript">
  16:  //<![CDATA[
  17:  var theForm = document.forms['form1'];
  18:  if (!theForm) {
  19:      theForm = document.form1;
  20:  }
  21:  function __doPostBack(eventTarget, eventArgument) {
  22:      if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
  23:          theForm.__EVENTTARGET.value = eventTarget;
  24:          theForm.__EVENTARGUMENT.value = eventArgument;
  25:          theForm.submit();
  26:      }
  27:  }
  28:  //]]>
  29:  </script>
  30:   
  31:   
  32:  <script src="/WebResource.axd?d=pynGkmcFUV13He1Qd6_TZAlhwiK26CMjFC_AwUoa5b3ERCspA6cmt_C-L8IOpCe633BVnc0wcDgTvonIIsSvwQ2&amp;t=634776373276709129" type="text/javascript"></script>
  33:   
  34:   
  35:  <script src="/Scripts/jquery-1.8.0.js" type="text/javascript"></script>
  36:  <script src="/WebResource.axd?d=x2nkrMJGXkMELz33nwnakEDhIJdn4zA9e1UqVq1SVvHhRhIprKEH70Wnr0YNmajC6LdVxQkRSvYza9nzCfZpzIEPGw7MYTdtpXpxdmoJjww1&amp;t=634776373276709129" type="text/javascript"></script>
  37:  <script type="text/javascript">
  38:  //<![CDATA[
  39:  function WebForm_OnSubmit() {
  40:  if (typeof(ValidatorOnSubmit) == "function" && ValidatorOnSubmit() == false) return false;
  41:  return true;
  42:  }
  43:  //]]>
  44:  </script>
  45:   
  46:  <div class="aspNetHidden">
  47:   
  48:      <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="+364tW9Dc7pDt6plQ90xe5FouuoNJLAEzbosO0J1tGmDKGpwQcxZ1kdqIV/tRvjZENOFLgzZM85V7T0z3t6I607wioiuB8cTrjZfCFSxHIPE/QbqekiEkZw9CeWGtKKGd2SzLZyMEXvyjxGP4xzOcHDDG0s00+EWD0Gay9W4uDXNzzVdNiwpoNp6dSj21Rvzuttb/+4L1dlkpikZJVdSig==" />
  49:  </div>
  50:      <div>
  51:          <table>
  52:              <tr>
  53:                  <td>Nombre:</td>
  54:                  <td>
  55:                      <input name="txtNombre" type="text" id="txtNombre" style="width:300px;" />
  56:                      <span data-val-controltovalidate="txtNombre" data-val-errormessage="*" id="requiredNombre" data-val="true" data-val-evaluationfunction="RequiredFieldValidatorEvaluateIsValid" data-val-initialvalue="" style="visibility:hidden;">*</span>
  57:                  </td>
  58:              </tr>
  59:              <tr>
  60:                  <td>Correo:</td>
  61:                  <td>
  62:                      <input name="txtCorreo" type="text" id="txtCorreo" style="width:300px;" />
  63:                      <span data-val-controltovalidate="txtCorreo" data-val-errormessage="*" id="requiredCorreo" data-val="true" data-val-evaluationfunction="RequiredFieldValidatorEvaluateIsValid" data-val-initialvalue="" style="visibility:hidden;">*</span>
  64:                  </td>
  65:              </tr>
  66:              <tr>
  67:                  <td>Usuario:</td>
  68:                  <td>
  69:                      <input name="txtUsuario" type="text" id="txtUsuario" style="width:300px;" />
  70:                      <span data-val-controltovalidate="txtUsuario" data-val-errormessage="*" id="requiredUsuario" data-val="true" data-val-evaluationfunction="RequiredFieldValidatorEvaluateIsValid" data-val-initialvalue="" style="visibility:hidden;">*</span>
  71:                  </td>
  72:              </tr>
  73:              <tr>
  74:                  <td>Clave:</td>
  75:                  <td>
  76:                      <input name="txtClave" type="password" id="txtClave" style="width:300px;" />
  77:                      <span data-val-controltovalidate="txtClave" data-val-errormessage="*" id="requiredClave" data-val="true" data-val-evaluationfunction="RequiredFieldValidatorEvaluateIsValid" data-val-initialvalue="" style="visibility:hidden;">*</span>
  78:                  </td>
  79:              </tr>
  80:              <tr>
  81:                  <td><input type="submit" name="btnGuardar" value="Guardar" onclick="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(&quot;btnGuardar&quot;, &quot;&quot;, true, &quot;&quot;, &quot;&quot;, false, false))" id="btnGuardar" /></td>
  82:              </tr>
  83:          </table>
  84:      </div>
  85:      </form>
  86:  </body>
  87:  </html>

Lo primero que observamos es que solo tenemos 87 líneas en contra de las 137 anteriores (bastantes menos no?), lo segundo es que ya no tenemos tanto código JavaScript y lo tercero es que aparecen nuevos atributos en los span, y esos atributos son los que ahora determinan las validaciones. Inicialmente el HTML de un span era:

   1:  <span id="requiredNombre" style="visibility:hidden;">*</span>

Y luego con la validación no intrusiva lista:

   1:  <span data-val-controltovalidate="txtNombre" data-val-errormessage="*" id="requiredNombre" data-val="true" data-val-evaluationfunction="RequiredFieldValidatorEvaluateIsValid" data-val-initialvalue="" style="visibility:hidden;">*</span>

Como se puede ver, se han generado nuevos atributos del tipo data-val-<…> los cuales determinan como se realizará la validación.

Espero les sea de utilidad este post, saludos!

4 comments

Leave a Reply

Your email address will not be published. Required fields are marked *