DataAnnotation с пользовательским ResourceProvider
Я создал пользовательский ResourceProvider
, чтобы вытащить информацию о локализации из базы данных. Теперь я хочу использовать DataAnnotation
для добавления проверки модели.
DataAnnotation
имеет свойства ErrorMessageResourceType
и ErrorMessageResourceName
, но ErrorMessageResourceType
принимает только System.Type
(т.е. скомпилированный файл ресурсов)
Есть ли способ получить DataAnnotation для использования настраиваемого ResourceProvider?
Ответы
Ответ 1
Я понимаю, что это старый вопрос, но хотелось добавить немного. Я оказался в той же ситуации и, похоже, не было никакой документации/блогации по этой теме. Тем не менее, я выяснил способ использования специализированного поставщика ресурсов с одной оговоркой. Оговорка в том, что я в приложении 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;
}
}
Ответ 2
Я использовал для этого достаточную проверку. Это экономит много времени. Это то, на что похож мой валидатор с глобализацией. Это означает, что вы не используете аннотации данных, но иногда данные anotations становятся немного большими и беспорядочными.
Вот пример:
(Errors.Required, Labels.Email и Errors.AlreadyRegistered находятся в моей папке с базовыми ресурсами.)
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?
...
}
}
Как я уже сказал, это аннотации аннотированных форматов, потому что у меня уже слишком много аннотаций по моим методам!
Ответ 3
Я добавлю свои выводы, так как мне пришлось бороться с этим. Может быть, это поможет кому-то.
Когда вы выходите из 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;
}
}
Ответ 4
Рассмотрим этот подход проверки.