Validación de formularios en ASP.NET MVC - Unobtrusive Validate

Cuando desarrollamos aplicaciones ASP.NET basadas en formularios web, es fundamental prestar especial atención a la seguridad de los datos que pueden ser enviados al 'Servidor' por los usuarios que las utilizan.

La validación de los datos una vez recibidos en el 'Servidor' es bastante obvia, ya que depende de nuestra habilidad como programador para discriminar los erróneos o malintencionados de los que realmente espera nuestra aplicación. Aún así, siempre es una buena práctica realizar también una validación de datos en el 'Cliente' (desde el propio explorador del usuario) para reducir la posibilidad de que al 'Servidor' lleguen datos incorrectos o potencialmente peligrosos para nuestra aplicación.

Como complemento al anterior Post 'Cómo recibir datos desde un formulario POST en ASP.NET MVC', a continuación veremos cómo realizar validaciones en 'Cliente' a formularios web Http POST, utilizando el potencial que nos brindan los Html Helpers de ASP.NET MVC, en conjunción con las librerías de validación de datos jQuery (Unobtrusive Validation).

Para comenzar crearemos un nuevo proyecto en Visual Studio del tipo Web application MVC framework 4.5. La aplicación consistirá en un simple formulario de inicio de sesión (login), suficiente como para ver en profundidad la validación en 'Cliente' de formularios web en ASP.NET MVC.

login-app

El Modelo

En primer lugar crearemos un 'Modelo' de datos que represente la información que el usuario enviará a la aplicación a través del formulario web. Este 'Modelo' deberá proporcionar toda la información de validación posible sobre de los datos que lo componen a través del uso de atributos de definición de metadatos (DataAnnotations).

    public class LoginDataModel
    {
        [Display(Name = "Correo electrónico")]
        [Required(ErrorMessage = "Este campo es requerido.")]
        [RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", 
            ErrorMessage = "Dirección de Correo electrónico incorrecta.")]
        [StringLength(100 , ErrorMessage = "Longitud máxima 100")]
        [DataType(DataType.EmailAddress)]
        public string Email { get; set; }

        [Display(Name = "Contraseña")]
        [Required(ErrorMessage = "Este campo es requerido.")]
        [StringLength(15, ErrorMessage = "Longitud entre 6 y 15 caracteres.", 
                      MinimumLength = 6)]
        [DataType(DataType.Password)]
        public string Password { get; set; }

        [Display(Name = "Recordarme")]
        public bool RememberMe { get; set; }
    }

La Vista

Para construir la Vista utilizaremos los controles Html Helpers de MVC, ya que queremos que sea el propio framework el que "construya"  las etiquetas Html de nuestro formulario, añadiéndoles los atributos de validación necesarios en función de los metadatos (DataAnnotations) del 'Modelo'. Todo esto lo veremos en profundidad más adelante, de momento, crearemos la 'Vista' de la siguiente forma:

@model LoginDataModel

<link href="~/Content/bootstrap.css" rel="stylesheet" />
<link href="~/Content/Site.css" rel="stylesheet" />

<div class="row">
    @using (Html.BeginForm("Index", "Home", FormMethod.Post))
    {
        @Html.AntiForgeryToken()
        <div class="col-md-6 col-md-offset-2 form-horizontal">
            <br />
            @Html.LabelFor(x => x.Email)
            @Html.TextBoxFor(x => x.Email, new { @class = "form-control", autofocus = "autofocus" })
            @Html.ValidationMessageFor(x => x.Email, null, new { @class = "text-danger" })
            <br />

            @Html.LabelFor(x => x.Password)
            @Html.PasswordFor(x => x.Password, new { @class = "form-control" })
            @Html.ValidationMessageFor(x => x.Password, null, new { @class = "text-danger" })
            <br />

            @Html.LabelFor(x => x.RememberMe)
            @Html.CheckBoxFor(x => x.RememberMe, new { @class = "" })
            <br />

            <button class="btn btn-primary" type="submit">
                Iniciar sesión
            </button>
        </div>
    }
</div>

<script src="~/Scripts/jquery-3.3.1.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="~/Scripts/bootstrap.js"></script>

Como podemos ver en el código, debemos incluir las librerías jQuery de validación de datos en nuestra vista,

<script src="~/Scripts/jquery-3.3.1.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>

jQuery y el plugin de validación (jquery.validate.js) los suele instalar automáticamente Visual Studio al crear un nuevo proyecto ASP.NET MVC. En cuanto a la librería de validación jQuery unobtrusive (jquery.validate.unobtrusive.js) se puede descargar vía NuGet buscando la siguiente referencia "Microsoft.jQuery.Unobtrusive.Validation".

El Controlador

En cuanto al 'Controlador', la estructura es bastante simple. Crearemos una nueva 'Acción' Index del tipo [HttpPost], donde recibiremos como parámetro el 'Modelo' con los datos del formulario desde la 'Vista'. Aquí, realizaremos una segunda validación en 'Servidor' mediante la propiedad ModelState.IsValid, para asegurarnos otra vez de la validez de los datos.

    public class HomeController : Controller
    {
        [HttpGet]
        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Index(LoginDataModel loginDataModel)
        {
            if (ModelState.IsValid)
                return RedirectToAction("Ok");
            else
                return View(loginDataModel);
        }

        public ActionResult Ok()
        {
            // Aquí código validación correcta...
            return View();
        }
    }

La configuración

Antes de probar nuestra aplicación, debemos establecer a 'true' las propiedades ClientValidationEnabledUnobtrusiveJavaScriptEnabled. Esta configuración la podemos realizar de varias formas:

Desde el Web.Config en la sección <appSettings>.

<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>

Desde el archivo Global.asax en el método Application_Start().

protected void Application_Start()
{
    HtmlHelper.ClientValidationEnabled = true;
    HtmlHelper.UnobtrusiveJavaScriptEnabled = true;
}

O desde la propia 'Vista'

@{
    Html.EnableClientValidation(true);
    Html.EnableUnobtrusiveJavaScript(true);
}

El resultado

Una vez terminada nuestra aplicación, la pondremos en marcha para para ver su funcionamiento. Si todo ha ido bien, podremos comprobar cómo la validación de los datos del formulario se realiza desde el mismo explorador, sin enviar en ningún momento la página al 'Servidor'. Además el botón de 'Iniciar sesión' no realizará el 'Submit' del formulario hasta que los datos introducidos sean correctos.

login-validate

También podemos ver como al introducir valores incorrectos, aparecen de forma dinámica los mensajes de error informativos que definimos en el 'Modelo' de datos en su momento. Toda esta funcionalidad de validación en 'Cliente', la proporcionan las librerías de validación de jQuery (Unobtrusive Validation) en conjunción con los Html Helpers de MVC y los atributos de validación del 'Modelo' (DataAnnotations).

La validación (Unobtrusive Validation)

Como ya debemos haber deducido, todo este mecanismo de validación en 'Cliente' está soportado principalmente por las librerías jQuery de validación jquery.validate.jsjquery.validate.unobtrusive.js, pero ¿cómo funciona internamente el proceso de validación?, y ¿por qué lo llamamos validación 'Unobtrusive'?.

El JavaScript 'Unobtrusive' o "no obstructivo" es un "paradigma" de utilización del lenguaje JavaScript en desarrollos web, que implica básicamente la separación del código de 'Scripting' de lo que es la página web en sí (código Html).

Si observamos el código fuente de nuestra aplicación, podemos ver que no existe ningún 'Script' de validación "inyectado" en tiempo de "construcción" de la página. Pero, por otra parte, sí podemos observar que las etiquetas Html de nuestro formulario, contienen una serie de atributos del tipo data-val- que representan las reglas de validación que en su momento definimos en el 'Modelo' de datos:

...
<label for="Email">Correo electr&#243;nico</label>
<input autofocus="autofocus" class="form-control" data-val="true" data-val-length="Longitud máxima 100" data-val-length-max="100" data-val-regex="Dirección de Correo electrónico incorrecta." data-val-regex-pattern="\w+([-+.&#39;]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" data-val-required="Este campo es requerido." id="Email" name="Email" type="text" value="" />
<span class="field-validation-valid text-danger" data-valmsg-for="Email" data-valmsg-replace="true"></span>

<label for="Password">Contrase&#241;a</label>
<input class="form-control" data-val="true" data-val-length="Longitud entre 6 y 15 caracteres" data-val-length-max="15" data-val-length-min="6" data-val-required="Este campo es requerido." id="Password" name="Password" type="password" />
<span class="field-validation-valid text-danger" data-valmsg-for="Password" data-valmsg-replace="true"></span>
...

Estos atributos data-val- de las etiquetas Html, serán entonces utilizados por la librería jquery.validate.unobtrusive.js para implementar en tiempo real el mecanismo de validación en 'Cliente', cumpliendo así el paradigma "no obstructivo" de separación del código JavaScript de la página Html.

Pero, ¿Que ocurriría si deshabilitamos la validación 'Unobtrusive' en nuestra aplicación?, hagamos la prueba:

Desde el web.config, estableceremos a 'false' la propiedad UnobtrusiveJavaScriptEnabled.

<add key="UnobtrusiveJavaScriptEnabled" value="false"/>

Ejecutamos de nuevo nuestra aplicación, y volvemos a observar el código fuente de nuestra página. Podemos ver en el código que los atributos data-val- han desaparecido de las etiquetas Html, y por otra parte, se ha "inyectado" un 'Script' de validación en la página, incumpliendo así los principios "no obtructivos" que anteriormente habíamos aplicado.

...
<label for="Email">Correo electr&#243;nico</label>
<input autofocus="autofocus" class="input-validation-error form-control" id="Email" name="Email" type="text" value="" />
<span class="field-validation-error text-danger" id="Email_validationMessage">Este campo es requerido.</span>

<label for="Password">Contrase&#241;a</label>
<input class="input-validation-error form-control" id="Password" name="Password" type="password" />
<span class="field-validation-error text-danger" id="Password_validationMessage">Este campo es requerido.</span>
...
<script type="text/javascript">
//<![CDATA[
if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({"Fields":[{"FieldName":"Email","ReplaceValidationMessageContents":true,"ValidationMessageId":"Email_validationMessage","ValidationRules":[{"ErrorMessage":"Dirección de Correo electrónico incorrecta.","ValidationParameters":{"pattern":"\\w+([-+.\u0027]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"},"ValidationType":"regex"},{"ErrorMessage":"Este campo es requerido.","ValidationParameters":{},"ValidationType":"required"},{"ErrorMessage":"Longitud máxima 100","ValidationParameters":{"max":100},"ValidationType":"length"}]},{"FieldName":"Password","ReplaceValidationMessageContents":true,"ValidationMessageId":"Password_validationMessage","ValidationRules":[{"ErrorMessage":"Este campo es requerido.","ValidationParameters":{},"ValidationType":"required"},{"ErrorMessage":"Longitud entre 6 y 15 caracteres","ValidationParameters":{"min":6,"max":15},"ValidationType":"length"}]}],"FormId":"form0","ReplaceValidationSummary":false});
//]]>
</script>
...

En esta situación, podríamos suponer que este nuevo 'Script' de validación "inyectado", será el encargado de sustituir a la configuración de validación que anteriormente realizaban los atributos data-val-, pero, desafortunadamente no es del todo así.

Tal y como está configurada nuestra aplicación en este momento, la validación en Cliente no funcionará, y el motivo está en que jQuery 'Unobtrusive' solo funciona con atributos data-val-. Entonces, ¿para que sirve este 'Script' que el framework MVC ha "inyectado" en nuestra página?, la solución está en la alternativa: Mvc Ajax Validation.

La alternativa (Mvc Ajax Validation)

Antes de que Microsoft implementara el sistema de validación jQuery 'Unobtrusive' para su framework ASP.NET MVC, las validaciones en 'Cliente' se realizaban mediante librerías JavaScript y Ajax (Mvc Ajax Validation). Este sistema de validación, utilizaba el 'Script' "inyectado" que anteriormente vimos para validar en 'Cliente' los campos de un formulario POST.

Para probar esta funcionalidad en nuestra aplicación, debemos incluir en nuestra 'Vista' las librerías Ajax de validación. La descarga la podemos hacer vía NuGet (Mvc Ajax Validation).

<script src="~/Scripts/MicrosoftAjax.js"></script>
<script src="~/Scripts/MicrosoftMvcValidation.js"></script>
<script src="~/Scripts/MicrosoftMvcAjax.js"></script>

En cuanto a la configuración, debemos mantener a 'true' la propiedad ClientValidationEnabled en el Web.config (o donde la tengamos definida).

<add key="ClientValidationEnabled" value="true"/>

Con esta nueva configuración, la validación en 'Cliente' volverá a funcionar tal y como lo hacía anteriormente, pero esta vez incumpliendo el paradigma "no obstructivo" (Unobtrusive) de separación del código JavaScript de la página Html.

 

  Compartir


  Nuevo comentario

El campo Comentario es obligatorio.
El campo Nombre es obligatorio.

Enviando ...

  Comentarios

No hay comentarios para este Post.


Perfil para Rafael Acosta en Stack Overflow en español, preguntas y respuestas para programadores y profesionales de la informática.

  Etiquetas

.NET Core .NET Framework .NET MVC .NET Standard AJAX ASP.NET ASP.NET Core ASP.NET MVC Bootstrap Buenas prácticas C# Cookies Entity Framework Gráficos JavaScript jQuery JSON JWT PDF Pruebas Unitarias Seguridad SEO SOAP Sql Server SqLite Swagger Validación Web API Web Forms Web Services WYSIWYG

  Nuevos


  Populares















Utilizamos cookies propias y de terceros para mejorar nuestros servicios y ofrecerle una mejor experiencia de navegación. Si continúa navegando consideramos que acepta su uso. Más información   Acepto