3

У меня есть модель (упрощенный) следующим образом:ASP.NET MVC модель привязки и проверки заказа

public UserModel { 
    ... 
    public USState State {get; set; } 
    public string StateString {get; set; } 
    public Country Country {get; set; } 
    ... 
} 

правила проверки мне нужны:

  1. Если Country является США затем State необходимо.
  2. Если Country не является США, то StateString не требуется.

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

  1. CompareField - Это поле, которое оно будет использовать для проверки того, требуется ли подтверждение.
  2. CompareValue - Это значение, которое будет сравниваться с тем, чтобы решить, требуется ли подтверждение.
  3. CompareType - Вот как он будет сравнивать значение, чтобы решить, требуется ли проверка.

Так с этим, я обновить мою модель, как, например:

public UserModel { 
    ... 
    [RequiredIf("Country", Country.USA, EqualityType.Equals)]  
    public USState State {get; set; } 
    [RequiredIf("Country", Country.USA, EqualityType.NotEquals)] 
    public string StateString {get; set; } 
    [Required]             
    public Country Country {get; set; } 
    ... 
} 

Здесь я должен отметить, что моя также имеет проверки на стороне клиента RequiredIfAttribute. Это прекрасно работает.

Теперь о проблеме ...

Я вывешиваю следующие значения:

State = AL
StateString = нуль
Страна = США

Это соответствует моим правилам проверки и должно быть действительным. Вот , но. ModelState говорит мне, что это неверно. По-видимому, поле StateString требуется. Это не то, что я указал. Почему мои правила валидации не применяются, как ожидалось?

(Если вы знаете, что случилось в этот момент, то не чувствую себя обязанным прочитать остальную часть вопроса)

Итак, вот что происходит. RequiredIfAttribute запускается три раза. Но подождите, я использую его только дважды.Она в настоящее время запускается следующим образом:

  1. Trigger на StateString (это возвращается недопустимого)
  2. Trigger на State (это возвращается действительного)
  3. Trigger на StateString (это возвращается действует)

Это довольно странно. Он проверяет StateString дважды, первый раз, когда он проходит, второй раз он терпит неудачу. Участок утолщается ...

Я посмотрел на это дальше, чтобы найти, что первый раз он пытается проверить StateString, Countryне множества. Второй раз он пытается подтвердить StateString, Countryis set. Похоже, что первая попытка проверки StateString произошла до того, как моя модель была полностью привязана. Все свойства (не указаны в образце модели), которые ниже StateString (в коде) не связаны. Вторая попытка проверки StateString, все свойства связаны.

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

public UserModel { 
    ... 
    public Country Country {get; set; } 
    public USState State {get; set; } 
    public string StateString {get; set; } 
    ... 
} 

RequiredIfAttribute все еще вызывает в три раза выше, но ModelState говорит мне, что отправленные данные (как выше) теперь действительный, как волшебство!

Что я вижу это это (мои предположения):

1. Start binding (property by property, top to bottom in code (risky)) 
2. Arrive at `StateString` and decide to try and validate 
3. Finish binding 
4. Validate all properties 

У меня действительно есть два вопроса:
1. Почему такое поведение выставлялись?
2. Как я могу остановить это поведение?

+0

Как вам удалось решить эту проблему? –

ответ

1

В процессе связывания модели существует значительное количество сложностей. Комплексные модели будут полностью пересмотрены.

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

http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/ModelBinding/Binders/MutableObjectModelBinder.cs

Существует фаза пост-обработка:

// post-processing, e.g. property setters and hooking up validation 
ProcessDto(actionContext, bindingContext, dto); 
bindingContext.ValidationNode.ValidateAllProperties = true; // complex models require full validation 

Существует фаза предварительной обработки:

// 'Required' validators need to run first so that we can provide useful error messages if 
// the property setters throw, e.g. if we're setting entity keys to null. See comments in 
// DefaultModelBinder.SetProperty() for more information. 

Там, кажется, не быть в целом много способы повлиять на это, помимо внедрения собственного связующего для модели.

+0

Спасибо за ваш ответ. Я могу подтвердить, что мой пользовательский атрибут действительно расширяет 'RequiredAttribute'.Так что, если это не так, вы думаете, что поведение, которое я вижу, не будет выставлено? –

+0

Я действительно думаю, что это может решить проблему. Вы можете переопределить свойство IsRequired для возврата false, поскольку код, похоже, ищет это при создании списка требуемых 'ModelValidator' –

Смежные вопросы