ASP.NET MVC3: Validación remota

Muy buenas!

Una de las novedades que nos trae ASP.NET MVC3, con respecto a MVC2 es poder usar fácilmente la validación remota: eso es, desde cliente llamar a un método del servidor que nos diga si un dato (entrado p.ej. en un campo de texto es válido o no). Y cuando digo fácilmente me refiero a fácilmente, muy fácilmente.

Vamos a ver un ejemplo: para ello vamos a modificar la aplicación de ejemplo que crea MVC3 para que al darnos de alta, consulte si el usuario ya existe y si es el caso no nos deje. Os recuerdo que esa validación es Ajax, eso significa: el campo de texto pierda el foco se realizará la petición (en background) al servidor que comprobará si el usuario entrado ya existe y si es así mostrará un error en el campo de texto asociado.

Vamos pues, a verlo paso a paso 😉

1. Viendo que nos genera MVC3

Para empezar creamos un nuevo proyecto ASP.NET MVC3. Cuando os pida el template, usad el de Internet Application (no uséis el Empty). De esa manera MVC3 nos crea el esqueleto de la aplicación inicial:

image

El fichero AccountModels.cs tiene distintos Viewmodels que usan las acciones del controlador Account. La acción que da de alta un usuario es Register que está definida en el controlador Account:

[HttpPost]
public ActionResult Register(RegisterModel model)
{
// Código...
}

La acción usa la clase RegisterModel que es uno de los viewmodels definidos en AccountModels.cs:

public class RegisterModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }

[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string Email { get; set; }

[Required]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }

[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}

2. Habilitando la validación remota

La validación remota en MVC3 se habilita, como el resto de validaciones, usando DataAnnotations, concretamente con el atributo Remote. En nuestro caso queremos habilitar la validación remota sobre la propiedad UserName. Para ello añado el atributo Remote:

[Required]
[Display(Name = "User name")]
[Remote("CheckUserAvailability", "Account", ErrorMessage = "This user name is not allowed.")]
public string UserName { get; set; }

El primer parámetro es la acción que va a validar el campo, la segunda es el controlador. Finalmente ponemos el mensaje de error (igual que las otras validaciones).

3. Creando el código de validación

Finalmente tenemos que crear la acción del controlador:

[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public ActionResult CheckUserAvailability(string username)
{
var validUserName = Membership.FindUsersByName(username).Count == 0;
return Json(validUserName, JsonRequestBehavior.AllowGet);
}

Fijaos lo simple que es: Usamos el membership provider para ver si existe algún otro usuario con el mismo nombre, y devolvemos un booleano (codificado en json). El uso de [OutputCache] es para evitar que MVC me cachee los resultados de las peticiones.

Y listos! Con eso ya hemos terminado.

Podemos ejecutar la aplicación, registrar un usuario y luego intentar darnos de alta de nuevo y veremos el error:

image

4. Y que pasa “en la trastienda”?

Si inspeccionamos las peticiones veremos que cada vez que cambia el texto se realiza una petición Ajax. Esta vez en lugar de firebug he usado las Developer Tools de IE9 (pulsar F12 para que os aparezcan):

image

Estas son las peticiones que se realizan si entro “eiximenis” en el campo de nombre de usuario. Si las contáis veréis que faltan peticiones. Eso es simplemente he pulsado dos teclas  muy rápido y las peticiones supongo que no se encolan

Si miramos los detalles de una petición vemos lo siguiente:

image

Fijaos en el primer campo (Request) me indica la URL de la petición. En mi caso es /Account/CheckUserAvailability?UserName=eiximenis

Es decir se pasa el valor por querystring (eso no es problema alguno para MVC que soporta el binding de datos en el querystring desde siempre).

5. Y qué código me genera eso en el navegador?

Recordáis que MVC3 apuesta fuertamente por el unobstrusive javascript? Pues eso es lo que nos genera:

<input data-val="true" 
data-val-remote="This user name is not allowed."
data-val-remote-additionalfields="*.UserName"
data-val-remote-url="/Account/CheckUserAvailability"
data-val-required="The User name field is required."
id="UserName" name="UserName" type="text" value="" />

Precioso no? Nada de código javascript mezclado por ahí que “ensucie” el html: sólo atributos.

Los atributos data-val-remote-* son los que controlan la validación remota. Para que eso funcione, es necesario que los scripts siguientes estén referenciados:

  1. jquery-1.4.4.min.js
  2. jquery.validate.min.js
  3. jquery.validate.unobtrusive.min.js

Yo los tengo siempre colocados en mi página Master principal (Views/Shared/_Layout.cshtml si usas Razor).

6. Controlando algunos aspectos “avanzados”

Vamos a ver como controlar algunos aspectos más de la validación remota. P.ej. te puede interesar que la llamada a la acción de validación (CheckUserAvailability) se realice via POST y no via GET. Para ello simplemente usa la propiedad HttpMethod del atributo Remote:

[Remote("CheckUserAvailability", "Account",
HttpMethod = "POST", ErrorMessage = "This user name is not allowed.")]

Eso añade el atributo data-val-remote-type="POST" al campo HTML generado lo que fuerza que la petición sea usando POST.

Otra cosa interesante es que podemos enviar más de un parámetro a la acción quen realiza la “validación remota”. P.ej. imaginad que a CheckUserAvailability le queremos también pasar el password que ha introducido el usuario (vale, no tiene lógica en ese ejemplo, pero imaginadlo igual :p).

Para ello podemos usar la propiedad AdditionalFields del atributo Remote:

[Remote("CheckUserAvailability", "Account", HttpMethod = "POST",
AdditionalFields = "Password",
ErrorMessage = "This user name is not allowed.")]
public string UserName { get; set; }

Ahora si miramos de nuevo lo que nos manda la petición veremos que junto al campo UserName nos manda el valor del campo Password:

image

Tened presente que el valor de Password puede ser vacío (el usuario puede no haber introducido nada allí todavía). Pero lo importante de esto es que las validaciones remotas no están limitadas a validar UN SOLO campo.

Y con eso terminamos el post de las validaciones remotas en ASP.NET MVC3… Como podeis ver, es un método sumamente potente y sumamente fácil!

Un saludo! 😉

2 comentarios en “ASP.NET MVC3: Validación remota”

  1. Eduardo,

    ¿Sabes cómo se tiene que llamar el parámetro del Action en el Controller que valida cuando es una subpropiedad?. Quiero decir, si en vez de ser Username fuese Entity.Username por ejemplo.
    Muchas gracias de antemano.

Deja un comentario

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