Вопрос о привязке настраиваемой модели ASP.NET MVC 2

Фон

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

  1. Visa - * **** * 1234 (Сохранено)
  2. Mastercard - * **** * 9876 (сохранено)
  3. [Новая кредитная карта ...]
  4. [Новый электронный чек ...]

Используя jQuery, я переключаю скрытые DIV, содержащие либо информационную таблицу (в случае вариантов 1 или 2 для сохраненных способов оплаты), либо форму (в случае [новых] параметров).

Я использую строго типизированный класс в качестве модели представления, которая содержит (среди простых типов) класс CreditCard и класс Check. Каждый из этих классов использует валидаторы аннотаций данных, так как они используются в других частях сайта.

Проблема

Проблема возникает, когда пользователь отправляет форму. Я хотел бы использовать привязку модели для обработки сопоставления значений POST, но мне нужно, чтобы привязка и / или проверка срабатывала в зависимости от того, какой вариант выбрал пользователь. Например, если пользователь выбирает вариант 1 или 2 из приведенного выше списка, я не хочу, чтобы проверка модели (или, возможно, даже сама привязка) срабатывала для объектов CreditCard или Check.

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

Логика была бы довольно простой:

  • Если пользователь выбрал один из существующих способов оплаты, проверка кредитной карты или чека не требуется.
  • Если пользователь выбрал один из вариантов для создания нового способа оплаты, то необходимо привязать и проверить только выбранный метод (кредитная карта или чек).

Кажется, что расширение DefaultModelBinder - это правильный путь, поскольку я хотел бы, чтобы основа выполняла большую часть тяжелой работы без необходимости создавать настраиваемое связующее с нуля. Однако, глядя на доступные методы для переопределения, неясно, какой из них лучший:

  1. BindProperty - проблема в том, что мне в основном нужно смотреть на одно из свойств, чтобы определить, какие другие свойства должны быть связаны. Я не думаю, что могу контролировать порядок, в котором привязываются входящие свойства, и не хотел бы полагаться на порядок, в котором они установлены в HTML-форме.
  2. OnModelUpdated - К этому моменту уже слишком поздно. Была запущена проверка привязки из аннотаций к данным, и ModelState был обновлен. Мне пришлось бы перебрать ModelState и удалить несущественные ошибки.
  3. OnPropertyValidating - сначала я подумал, что это то место, где мне следует искать, но даже возврат TRUE для всех свойств (в качестве теста) приводит к тому, что ModelState содержит ошибки привязки.

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

Любая помощь по этому поводу будет принята с благодарностью.

Все возможные значения хранятся в раскрывающемся списке. Используя jQuery, я переключаю форму (для нового метода оплаты) и отображение (для существующего метода)


person dotariel    schedule 18.10.2010    source источник


Ответы (2)


Я решил попытаться полностью обойти привязку модели и использовать FormCollection, IValueProvider и TryUpdateModel внутри своего действия контроллера.

person dotariel    schedule 29.10.2010

Ваша проблема звучит как специализированный, чтобы быть помещенным в ModelBinder по умолчанию.

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

MVC 3 обещает предоставить более расширяемый ModelBinder, но по моему личному опыту, если только это не очень просто то, что вам нужно изменить, например, превращение пустых текстовых ящиков в "" вместо null, чем держаться подальше от вашей собственной реализации.

Альтернативный подход - использовать существующую функциональность ModelBinder по частям и использовать такие вещи, как Ignore method parameters, для очистки:

if( myModel.IsNewPayment )
   UpdateModel( myModel.Payment, "exclude everything else" );

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

person John Farrell    schedule 18.10.2010
comment
jfar, я не понимаю, как это смешивает бизнес-логику с логикой представления. Я рассматриваю это как логику проверки ввода, где я действительно хочу иметь своего рода дифференцирующую проверку. - person dotariel; 19.10.2010
comment
@ XSaint32 - дифференцированная проверка - это для меня бизнес-логика, проверка ввода - это не пустая строка, это действительное datetime, пользователь указал цену, я пытаюсь вас предупредить, дифференцирующая проверка - это не то, что связывает модель хорош в предоставлении - person John Farrell; 19.10.2010
comment
@jfar - Под дифференциацией проверки я подразумеваю то, что я не хочу, чтобы связыватель модели по умолчанию выдавал ошибки привязки для полей, не относящихся к запросу. На мой взгляд, проверка ЗАПРОСА пользователя и взаимодействие с вводом пользователя - это презентация, а не бизнес-логика. Я бы согласился с вами, если бы я пытался проверить номер самой кредитной карты или сравнить его со списком заблокированных карт. Видя, как это просто говорит: «Эй, если пользователь нажимает на Вариант 1, не беспокойтесь о том, ввел ли он значения для кредитной карты». - person dotariel; 19.10.2010
comment
В любом случае я решил попытаться полностью обойти привязку модели и использовать FormCollection, IValueProvider и TryUpdateModel внутри своего действия контроллера. - person dotariel; 19.10.2010
comment
@jfar - Да. Я имел в виду автоматическую привязку модели. :) - person dotariel; 20.10.2010