DataAnnotation с пользовательским ResourceProvider

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

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

Есть ли способ заставить DataAnnotation использовать пользовательский ResourceProvider?

Я понимаю, что это старый вопрос, но хотелось добавить немного. Я оказался в той же ситуации и, похоже, не было никакой документации / блогации по этой теме. Тем не менее, я выяснил способ использования специализированного поставщика ресурсов с одной оговоркой. Предостережение в том, что я в приложении 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, чтобы передать тип проверяемого classа. Под этим я подразумеваю, что если я в classе клиента и проверяю свойство FirstName, я бы передал typeof (customer) . Я делаю это, потому что в моей базе данных базы данных я использую полное имя classа (namespace + classname) в качестве ключа (так же, как URL-адрес страницы используется в asp.net).
    • MVC_HtmlHelpers.Localize – это просто простая shell для моего настраиваемого поставщика ресурсов

(Полу-украденный) код помощника выглядит так ….

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

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

Вот пример:

(Errors.Required, Labels.Email и Errors.AlreadyRegistered находятся в моей папке с базовыми ресурсами).

 public class CreateEmployerValidator : AbstractValidator { 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? ... } } 

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

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

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

Пользовательский атрибут:

 public class LocalizedRequiredAttribute : RequiredAttribute, IClientValidatable { public LocalizedRequiredAttribute(string resourceName) { this.ErrorMessage = Resources.GetResource(resourceName); } public IEnumerable 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; } }