2009-12-04 15 views
19

He creado un personalizado ResourceProvider para extraer información de localización de una base de datos. Ahora quiero usar DataAnnotation para agregar validación al modelo.DataAnnotation con ResourceProvider personalizado

DataAnnotation tiene ErrorMessageResourceTypeErrorMessageResourceName y propiedades, pero sólo acepta ErrorMessageResourceTypeSystem.Type (es decir, un archivo de recursos compilado)

¿Hay alguna manera de obtener DataAnnotation utilizar la resourceProvider personalizada?

Respuesta

5

Me doy cuenta de que esta es una pregunta antigua, pero quería agregar un poco. Me encontré en la misma situación y no parece haber documentación/blogumentación sobre este tema. Sin embargo, descubrí una forma de utilizar un proveedor de recursos personalizado, con una advertencia. La advertencia es que estoy en una aplicación MVC, así que todavía tengo HttpContext.GetLocalResourceObject() disponible. Este es el método que usa asp.net para localizar artículos. La ausencia del objeto recurso no le impide escribir nuestra propia solución, incluso si es una consulta directa de las tablas DB. Sin embargo, pensé que valía la pena señalarlo.

Si bien no estoy muy contento con la siguiente solución, parece que funciona. Para cada atributo de validación que quiero usar, heredo de dicho atributo y sobrecargo el IsValid(). La decoración se ve así:

[RequiredLocalized(ErrorMessageResourceType= typeof(ClassBeginValidated), ErrorMessageResourceName="Errors.GenderRequired")] 
public string FirstName { get; set; } 

El nuevo atributo tiene el siguiente aspecto:

public sealed class RequiredLocalized : RequiredAttribute { 

    public override bool IsValid(object value) { 

     if (! (ErrorMessageResourceType == null || String.IsNullOrWhiteSpace(ErrorMessageResourceName)) ) { 
      this.ErrorMessage = MVC_HtmlHelpers.Localize(this.ErrorMessageResourceType, this.ErrorMessageResourceName); 
      this.ErrorMessageResourceType = null; 
      this.ErrorMessageResourceName = null; 
     } 
     return base.IsValid(value); 
    } 
} 

Notas

  • lo necesario para decorar su código con el atributo derivado, no la norma uno
  • Estoy usando ErrorMessageResourceType para pasar el tipo de la clase que se está validando. Con esto me refiero a si estoy en una clase de cliente y validando la propiedad FirstName pasaría typeof (cliente). Lo hago porque en el back-end de mi base de datos estoy usando el nombre completo de la clase (namespace + classname) como clave (de la misma manera que se usa una URL de página en asp.net).
    • MVC_HtmlHelpers.Localize es sólo un envoltorio sencillo para el profesional del recurso personalizado

El código auxiliar (semi-robo) se parece a esto ....

public static string Localize (System.Type theType, string resourceKey) { 
    return Localize (theType, resourceKey, null); 
} 
public static string Localize (System.Type theType, string resourceKey, params object[] args) { 
    string resource = (HttpContext.GetLocalResourceObject(theType.FullName, resourceKey) ?? string.Empty).ToString(); 
    return mergeTokens(resource, args); 
} 

private static string mergeTokens(string resource, object[] args)  { 
    if (resource != null && args != null && args.Length > 0) { 
     return string.Format(resource, args); 
    } else { 
     return resource; 
    } 
} 
3

He usado la validación con fluidez para lograr esto. Me ahorra mucho tiempo. Así es como se ve mi validador Globalizado. Significa que no utiliza anotaciones de datos, pero a veces las anotaciones de datos se vuelven un poco grandes y desordenadas.

Aquí se muestra un ejemplo:

(errors.required, Labels.Email y Errors.AlreadyRegistered están en mi carpeta de recursos blobal.)

public class CreateEmployerValidator : AbstractValidator<CreateEmployerModel> { 
    public RegisterUserValidator() { 
     RuleFor(m => m.Email) 
      .NotEmpty() 
      .WithMessage(String.Format(Errors.Required, new object[] { Labels.Email })) 
      .EmailAddress() 
      .WithMessage(String.Format(Errors.Invalid, new object[] { Labels.Email })) 
      .Must(this.BeUniqueEmail) 
      .WithMessage(String.Format(Errors.AlreadyRegistered, new object[] { Labels.Email })); 
    } 

    public bool BeUniqueEmail(this IValidator validator, string email) { 
     //Database request to check if email already there? 
     ... 
    }  
} 

Como dije, es un alejamiento anotaciones forma de datos, sólo porque ya tengo demasiadas anotaciones en mis métodos ya!

2

Agregaré mis hallazgos ya que tuve que pelear con esto. Quizás ayudará a alguien.

Cuando se deriva de RequiredAttribute, parece romper la validación del lado del cliente. Para solucionarlo, implementé IClientValidatable e implementé el método GetClientValidationRules. Resources.GetResources es el método estático de ayuda que tengo que envuelve HttpContext.GetGlobalResourceObject.

El atributo requerido aduana:

public class LocalizedRequiredAttribute : RequiredAttribute, IClientValidatable 
{ 
    public LocalizedRequiredAttribute(string resourceName) 
    { 
     this.ErrorMessage = Resources.GetResource(resourceName); 
    } 

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     yield return new ModelClientValidationRule 
     { 
      ErrorMessage = this.ErrorMessage, 
      ValidationType= "required" 
     }; 
    } 
} 

Uso:

[LocalizedRequired("SomeResourceName")] 
public string SomeProperty { get; set; } 

Y mi Recursos de ayuda si alguien está interesado:

public class Resources 
{ 
    public static string GetResource(string resourceName) 
    { 
     string text = resourceName; 
     if (System.Web.HttpContext.Current != null) 
     { 
      var context = new HttpContextWrapper(System.Web.HttpContext.Current); 
      var globalResourceObject = context.GetGlobalResourceObject(null, resourceName); 
      if (globalResourceObject != null) 
       text = globalResourceObject.ToString(); 
     } 

     return text; 
    } 
} 
Cuestiones relacionadas