ASP.NET MVC–Traduciendo las validaciones de CompareAttribute

Muy buenas! Seguimos ese tour de force sobre las traducciones de los mensajes de validación de Data Annotations.

En el primer post de esta serie vimos como crear adaptadores de atributos para permitirnos fácilmente y a nivel centralizado establecer las propiedades ErrorMessageResourceName y ErrorMessageResourceType.

El post terminaba con una lista de los distintos adaptadores que tiene ASP.NET MVC y que podíamos usar como clases base. Hay adaptadores definidos para casi todos los atributos de Data Annotations (Required, StringLength,…) pero no hay ninguno para el CompareAttribute. El atributo Compare no se usa mucho, ya que valida que dos propiedades tengan el mismo valor. El clásico uso es en formularios de registro donde el usuario debe introducir una contraseña dos veces para evitar que haya ningún error.

Pero el hecho de que ASP.NET MVC no incluya ningún adaptador base para dicho atributo no nos impide crearnos el nuestro y aplicar la misma técnica para traducir los mensajes de validación de dicho atributo. Para ello derivaremos de la clase DataAnnotationsModelValidator<T> (siendo T el tipo del atributo, en este caso el CompareAttribute).

La principal diferencia es que ahora debemos generar las validaciones de cliente, sobreescribiendo el método GetClientValidationRules().

Pese a todo, el código sigue siendo muy sencillo:

  1. public class LocalizedCompareAdapter : DataAnnotationsModelValidator<System.ComponentModel.DataAnnotations.CompareAttribute>
  2. {
  3.     public LocalizedCompareAdapter(ModelMetadata metadata, ControllerContext context, CompareAttribute attribute)
  4.         : base(metadata, context, attribute)
  5.     {
  6.         attribute.ErrorMessageResourceName = "Compare";
  7.         attribute.ErrorMessageResourceType = typeof(Resources.Messages);
  8.     }
  9.  
  10.     public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
  11.     {
  12.         var other = Attribute.OtherProperty;
  13.         return new[] { new ModelClientValidationEqualToRule(base.ErrorMessage, other) };
  14.     }
  15. }

En el método GetClientValidationRules devolvemos las validaciones de cliente. En este caso, queremos comparar dos propiedades así que devolvemos una ModelClientValidationEqualToRule, a la cual le pasamos el nombre de la otra propiedad. Recuerda que el [Compare] se aplica a una  propiedad (p. ej. ConfirmPassword) y se coloca el nombre de la otra propiedad (p. ej. Password):

  1. public string Password { get; set; }
  2. [Compare("Password")]
  3. public string ConfirmPassword { get; set; }

En este caso es la propiedad ConfirmPassword la que está decorada con el CompareAttribute, por lo tanto esta es la contendrá la regla de validación en cliente. De hecho el código HTML generado por los helpers Html.TextBoxFor para esas dos propiedades es:

  1. <input id="Password" name="Password" type="text" value="" />
  2. <input data-val="true" data-val-equalto="Los valores de ConfirmPassword y Password deben ser iguales"
  3.        data-val-equalto-other="Password" id="ConfirmPassword" name="ConfirmPassword" type="text" value="" />

Se puede ver que el <input /> que se corresponde a Password no tiene validaciones aplicadas y que es el <input /> que corresponde a ConfirmPassword el que tiene las validaciones de cliente aplicadas.

Podemos ver que el mensaje de error (data-val-equalto) está en castellano porque en mi fichero de recursos (Messages.es.resx) tengo la entrada “Compare”que es la que usa nuestro adaptador de recursos:

image

¡Y listos! Hemos visto como el hecho de que ASP.NET MVC  no provea un adaptador base no nos impide usar DataAnnotationsModelValidator<T> para crearnos nuestro propio adaptador, con la salvedad de que debemos indicar las validaciones de cliente a generar (las de servidor no son necesarias).

PD: Por supuesto debemos registrar ese adaptador de atributo como vimos en el post dedicado a los adaptadores:

  1. DataAnnotationsModelValidatorProvider.RegisterAdapter(
  2.     typeof (System.ComponentModel.DataAnnotations.CompareAttribute),
  3.     typeof (LocalizedCompareAdapter));

Un saludo!

Deja un comentario

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