2009-12-04 5 views
19

Я создал пользовательский ResourceProvider, чтобы вытащить информацию о локализации из базы данных. Теперь я хочу использовать DataAnnotation, чтобы добавить подтверждение модели.DataAnnotation с пользовательским ResourceProvider

DataAnnotation имеет ErrorMessageResourceType и ErrorMessageResourceName свойства, но ErrorMessageResourceType принимает только System.Type (т.е. скомпилированный файл ресурса)

Есть ли способ, чтобы получить DataAnnotation использовать пользовательские ResourceProvider?

ответ

5

Я понимаю, что это старый вопрос, но хотелось добавить немного. Я оказался в той же ситуации и, похоже, не было никакой документации/блогации по этой теме. Тем не менее, я выяснил способ использования специализированного поставщика ресурсов с одной оговоркой. Предостережение в том, что я в приложении MVC, поэтому у меня все еще есть HttpContext.GetLocalResourceObject(). Это метод, который использует asp.net для локализации элементов. Отсутствие ресурсного объекта не мешает вам писать собственное решение, даже если оно является прямым запросом таблиц БД. Тем не менее, я думал, что стоит отметить.

Хотя я не очень доволен следующим решением, он, похоже, работает. Для каждого атрибута проверки я хочу использовать наследование у указанного атрибута и перегрузить IsValid(). Украшение выглядит следующим образом:

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

новый атрибут выглядит следующим образом:

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); 
    } 
} 

Примечание

  • Вы должны украсить свой код с производным атрибутом, а не стандартным один
  • Я использую ErrorMessageResourceType, чтобы передать тип проверяемого класса. Под этим я имею в виду, если бы я был в классе клиента и проверял свойство FirstName, я бы передал typeof (customer). Я делаю это, потому что в моей базе данных базы данных я использую полное имя класса (namespace + classname) в качестве ключа (так же, как URL-адрес страницы используется в asp.net).
    • MVC_HtmlHelpers.Localize это простая оболочка для моего пользовательского поставщика ресурсов

(пол-украдено) вспомогательный код выглядит следующим образом ....

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

Я воспользовался беглою валидацией для достижения этой цели. Это экономит много времени. Это то, на что похож мой валидатор с глобализацией. Это означает, что вы не используете аннотации данных, но иногда данные anotations становятся немного большими и беспорядочными.

Вот пример:

(Errors.Required, Labels.Email и Errors.AlreadyRegistered в моей папке 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? 
     ... 
    }  
} 

Как я уже сказал, это отход аннотаций формы данных, только потому, что у меня уже есть слишком много аннотаций на мои методы уже!

2

Я добавлю свои выводы, так как мне пришлось сражаться с этим. Может быть, это поможет кому-то.

Когда вы выходите из RequiredAttribute, он, похоже, нарушает проверку на стороне клиента. Поэтому, чтобы исправить это, я реализовал IClientValidatable и реализовал метод GetClientValidationRules. Resources.GetResources - это статический вспомогательный метод, который у меня есть, который обертывает объект HttpContext.GetGlobalResourceObject.

Обычай Обязательный атрибут:

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" 
     }; 
    } 
} 

Использование:

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

И мой помощник ресурсы, если кому-то интересно:

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; 
    } 
}