Проблема проверки модели MVC 3 - надзор или проектирование - PullRequest
20 голосов
/ 16 сентября 2011

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

Не вдаваясь в детали, вот основная идея:

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

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

   //Return the results
}

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

ОДНАКО ...

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

Хааааааааааааааааааааааааааааааааааааааааааааа)))))))))))))))))))))))))))))))))))))))) Я провел небольшое расследование и, конечно же, прямо в 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:)

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

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

Ответы [ 4 ]

4 голосов
/ 11 июля 2013

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

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

Затем в MyValidationAttribute.cs:

public class MyValidationAttribute
{
    private string PropertyName;

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

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

3 голосов
/ 16 сентября 2011

Josh

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

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

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

1 голос
/ 25 февраля 2013

Была такая же проблема, и этот вопрос поставил меня на правильный путь.Я исправил это, изменив свой пользовательский валидатор на заполнение MemberName при создании 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 });
}
1 голос
/ 08 мая 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...