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

Проблема проверки модели MVC 3 - надзор или дизайн

Я столкнулся с сценарием, где мне нужно было знать, какое свойство в настоящее время проверялось в пользовательском ValidationAttribute. Я предположил, что это будет легко в MVC 3, поскольку ValidationContext передается в метод IsValid.

Не вдаваясь в подробности, вот основная идея:

protected override ValidationResult IsValid(Object value, ValidationContext validationContext) {

   if (ShouldICareAboutYou(validationContext.MemberName))
   {
       //Do some stuff
   }

   //Return the results
}

Это казалось идеальным решением, и действительно, когда модульное тестирование моего пользовательского ValidationAttribute с помощью Validator.TryValidateObject, все работало красиво!

ОДНАКО...

При вызове TryUpdateModel или TryValidateModel внутри моего контроллера выполняется проверка, но ValidationContext.MemberName имеет значение null.

Whaa Huh?!?

Я сделал небольшое исследование и, конечно, прямо внутри DataAnnotationsModelValidator - это код... или его отсутствие.

public override IEnumerable<ModelValidationResult> Validate(object container) {
    // Per the WCF RIA Services team, instance can never be null (if you have
    // no parent, you pass yourself for the "instance" parameter).
    ValidationContext context = new ValidationContext(container ?? Metadata.Model, null, null); 
    context.DisplayName = Metadata.GetDisplayName();

    // Setting the MemberName here would be trivial!
    // However, philh told me not to. Something about
    // a guy named Josh who pushed him down on the playground
    // in middle school.

    //context.MemberName = Metadata.PropertyName; (Suck It, Josh!!!)

    ValidationResult result = Attribute.GetValidationResult(Metadata.Model, context); 
    if (result != ValidationResult.Success) {
        yield return new ModelValidationResult { 
            Message = result.ErrorMessage
        };
    }
} 

Я понимаю, что DisplayName может быть именем свойства, если в свойство не было применено DisplayAttribute. К сожалению, я не могу заниматься гипотезами. Мне нужно знать точно, что такое имя свойства.

Так в чем заключена сделка? Является ли это по дизайну или честному надзору. Если это недосмотр, тогда было бы здорово получить это исправление в MVC 4:)

Отказ от ответственности:

Добавленные комментарии в приведенном выше примере кода должны быть смешными. Я не знаю, и никогда не встречал Phil Haack. Из того, что я могу сказать, он кажется очень хорошим парнем. И толкание его в средней школе сделало бы меня королевским душем!

4b9b3361

Ответ 1

У меня была такая же проблема, и я решил передать имя свойства в качестве параметра в конструкторе атрибутов, а затем сохранить его в атрибуте. Например:

[MyValidationAttribute("MyProperty")]
public string MyProperty { get; set; }

Затем в MyValidationAttribute.cs:

public class MyValidationAttribute
{
    private string PropertyName;

    public MyValidationAttribute(string propertyName)
    {
        this.PropertyName = propertyName;
    }
}

Немного раздражает, что теперь мне нужно дважды ввести имя моего имущества, но оно решает проблему.

Ответ 2

Джош

Разочарование, да.

Однако для ваших целей вы можете создать свой собственный класс, наследующий от DataAnnotationsModelValidator, переопределить метод Validate() и раскомментировать эту строку кода, которая насмехается над вами. Затем в Global.asax.cs очистите ModelValidatorProviders.Providers и добавьте свой класс.

Не оптимальное решение, но оно поможет вам добраться туда.

Ответ 3

Вам нужно вызвать метод DataAnnotationsModelValidatorProvider.RegisterAdapter или DataAnnotationsModelValidatorProvider.RegisterAdapterFactory для вашего типа атрибута и предоставить свой пользовательский ModelValidator.

Ответ 4

Если бы та же проблема, и этот вопрос поставил меня на правильные пути. Я исправил его, изменив свой собственный валидатор, чтобы заполнить имя_пользователя, когда создается ValidationResult, так же (обратите внимание на второй параметр в конструкторе ValidationResult):

protected override ValidationResult IsValid(Object value, ValidationContext     validationContext) {

   if (ShouldICareAboutYou(validationContext.MemberName))
   {
       //Do some stuff
   }

   return new ValidationResult(FormatErrorMessage(validationContext.DisplayName), new string[] { validationContext.MemberName });
}