Это наиболее существенная причина, по которой ваши входные экраны не должны быть тесно связаны с вашей моделью. Этот вопрос фактически появляется здесь на тэге MVC около 3-4 раз в месяц. Я бы обманул, если бы мог найти предыдущий вопрос, и некоторые обсуждения комментариев здесь интересны. ;)
Проблема, с которой вы столкнулись, заключается в том, что вы пытаетесь объединить два разных контекста проверки модели в единую модель, которая дает сбой при большом количестве сценариев. Лучший пример - регистрация нового пользователя, а затем администратор редактирует поле пользователя позже. Вам необходимо подтвердить пароль на объекте пользователя во время регистрации, но вы не будете показывать поле пароля администратору, редактирующему данные пользователя.
Выбор для их обхода все неоптимальный. Я работал над этой проблемой для трех проектов, и реализация следующих решений никогда не была чистой и обычно разочаровывающей. Я постараюсь быть практичным и забуду все обсуждения DDD / db / model / hotnessofthemonth, которые есть у всех остальных.
1) Модели с несколькими представлениями
Наличие почти одинаковых view-моделей нарушает принцип DRY, но я чувствую, что затраты на этот подход действительно низкие. Обычно нарушение режима «СУХОЙ» увеличивает расходы на техническое обслуживание, но, по-моему, затраты на это самые низкие и не слишком велики. Говоря гипотетически, вы не меняете то, как максимальное количество символов в поле LastName может быть очень часто.
2) Динамические метаданные
В MVC 2 есть хуки для предоставления собственных метаданных для модели. При таком подходе вы можете использовать все, что используете для предоставления метаданных, исключая определенные поля на основе текущего HTTPRequest и, следовательно, Action и Controller. Я использовал этот метод для построения системы разрешений, управляемой базой данных, которая идет в БД и сообщает подклассу DataAnnotationsMetadataProvider для исключения значений на основе свойств, хранящихся в базе данных.
Этот метод отлично работает, но единственная проблема - проверка с помощью UpdateModel()
. Чтобы решить эту проблему, мы создали метод SmartUpdateModel()
, который также отправляется в базу данных и автоматически генерирует массив exclude string [], чтобы любые недопустимые поля не проверялись. Мы, конечно, кешировали это по соображениям производительности, так что это неплохо.
Просто хочу повторить, что мы использовали [ValidationAttributes] в наших моделях, а затем заменили их новыми правилами во время выполнения. Конечным результатом было то, что поле [Required]
User.LastName не было проверено, если у пользователя не было разрешения на доступ к нему.
3) Сумасшедший интерфейс Dynamic Proxy Thing
Последний метод, который я пытался использовать, - это использовать интерфейсы для ViewModels. В результате я получил объект User, унаследованный от таких интерфейсов, как IAdminEdit
и IUserRegistration
. IAdminEdit и IUserRegistration будут содержать атрибуты DataAnnotation, которые выполняют всю контекстно-зависимую проверку, например, свойство Password с интерфейсами.
Это потребовало некоторых хакерских действий и было более академическим упражнением, чем что-либо еще. Проблема с 2 и 3 заключается в том, что UpdateModel и поставщик DataAnnotationsAttribute необходимо настроить для ознакомления с этим методом.
Моим самым большим камнем преткновения было то, что я никогда не хотел отправлять весь пользовательский объект в представление, поэтому я использовал динамические прокси для создания экземпляров времени выполнения IAdminEdit
Теперь я понимаю, что это очень специфический вопрос xVal, но все пути к динамической проверке, подобные этой, ведут к настройке внутренних поставщиков метаданных MVC. Поскольку все содержимое метаданных является новым, на данном этапе нет ничего такого простого или простого. Работа, которую вам нужно сделать, чтобы настроить поведение валидации MVC, не сложна, но требует некоторых глубоких знаний о том, как работают все внутренние компоненты.