Подтвердить что ты не робот

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

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

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

Есть ли способ получить DataAnnotation для использования настраиваемого ResourceProvider?

4b9b3361

Ответ 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;
    }
}