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