Проверка MVC - держите DRY со служебным слоем - что лучше всего?

Я стараюсь придерживаться лучших многоуровневых методов проектирования и не хочу, чтобы мой MVC-контроллер взаимодействовал с моим DAL (или любым IRepository, если на то пошло). Он должен пройти через уровень моего бизнес-сервиса для обеспечения правильных бизнес-правил и проверки. Проверка. Я не хочу выполнять проверку в контроллере с использованием различных атрибутов проверки (таких как [Обязательный]) на объектах модели домена, потому что это проливает свет на мой интерфейс. Не говоря уже о том, что эта услуга также может быть реализована через интерфейс WPF.

Поскольку моя проверка выполняется на моем уровне обслуживания, каковы наилучшие методы возврата значений в пользовательский интерфейс? Я не хочу "void addWhatever (int somethingsID)", потому что мне нужно знать, не получилось ли это. Должно ли это быть логическим? Должно ли это быть Enum? Должен ли я использовать обработку исключений? Или мне нужно вернуть некоторый объект IValidationDictionary, аналогичный тому, который использовался MVC при атрибуции атрибутов проверки для объектов модели? (что я мог бы использовать шаблон адаптера в пользовательском интерфейсе позже, если это необходимо)

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

У меня было несколько идей, все из которых не чувствуют себя хорошо. Я считаю, что ответ включает в себя объекты View-specific-model, но это приводит к проблеме целого картографирования, с которой нужно иметь дело, не говоря уже об этом, нарушает принцип DRY (не повторяйте сам). Какая практика?

Ответы

Ответ 1

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

Почему? Поскольку ваши требования к проверке вашего взгляда довольно часто отличаются от требований к проверке бизнес-объектов. Проверка ваших взглядов касается проверки подлинности определенного представления, а не того, что ваша бизнес-модель действительна.

Иногда эти два одинаковые, но если вы создаете приложение, чтобы представление требовало, чтобы бизнес-модель была действительной, вы блокируете себя в этом сценарии. Что произойдет, если вам нужно разбить создание объекта на две страницы? Что произойдет, если вы решите использовать сервисный уровень для веб-сервиса? Блокируя свой пользовательский интерфейс в сценарии валидации бизнес-уровня, вы сильно навредите тем решениям, которые вы можете предоставить.

Представление - это проверка ввода, а не проверка модели.

Ответ 2

Вот как я это сделал.

Измените ли ваш уровень сервиса исключения из правила бизнес-правила/валидации. Создайте свою собственную проверку Исключения для этого и включите некоторые свойства для хранения сведений об ошибке проверки - (например, какое свойство имеет ошибку проверки и что такое сообщение)

Затем создайте метод расширения в Exception, который скопирует детали ошибки в ModelState (я получил эту идею от Steve Sandersons довольно отличную "Pro Asp.Net MVC 2 Framework" ) - если вы сделаете это правильно, MVC выделит недопустимые поля, покажет ошибки в пользовательском интерфейсе и т.д.

Тогда ваш контроллер будет содержать что-то вроде этого

try
{
    Service.DoSomeThing();
}
catch (Exception err)
{
    err.CopyTo(ModelState);
}

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

Рассмотрим также передачу DTOs/Просмотр моделей в ваши представления и сопоставление объектов вашего домена с DTO и (наоборот), а не передачу объектов домена в ваши представления.

Затем модели DTOs/View могут находиться на уровне MVC, и вы можете украсить их атрибутами Validation и передать контроллеру их в представления - таким образом, используя встроенную проверку MVC.

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

Существует хорошая библиотека под названием AutoMapper, которая позволяет легко отображать объекты вашего домена на ваши DTO (и наоборот) без много шаблонов.

Ответ 3

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

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

  • Возвращает объекты XXXResult вместо void или primatives. Если ваш метод обслуживания - AddProduct, то возвращайте AddProductResult или более широко ProductServiceOperationResult. Этот результат содержит индикатор успеха/сбоя, а также дополнительную информацию.

  • Если вы используете WCF, используйте Контракты и исключения Fault.

Типичное мое прикладное решение MVC выглядит следующим образом:

  • Проект веб-сайта MVC
  • xxx.Model(проект, на который ссылается большинство слоев)
  • xxx.Услуги (проект)
  • xxx.DataAccess(проект, иногда слияние с сервисами)
  • другие при необходимости

Удачи!

Ответ 4

Проблема здесь - это проверка на уровне сервиса, но как получить эту информацию "назад" в веб-приложение. Что-то подобное мы обсудили немного назад, так как идея инъекции зависимостей явно вступает в игру здесь, если служба проверяет, вы не можете вызвать вызов службы в модели (например, если там реализован IValidateableObject, вы не хотите вызывать службу непосредственно)

Принятый подход:

Вариант 3: я не знал об этом раньше, но то, что кажется очень мощный способ создания валидаторов - использовать ModelValidator класс и соответствующий ModelValidatorProvider.

ASP.NET MVC 3: Проверка модели, когда требуется информация, внешняя по отношению к модели

Таким образом, в основном вы вводите валидатор (который будет в вашем уровне обслуживания), который должен быть разрешен посредством mvc без необходимости явного вызова локатора службы.

Ответ 5

Стивен советует в этом сценарии. В настоящее время я работаю над очень большим приложением MVC 3.0 с SOA и другими вещами. Таким образом, в ответ вы хотели бы заполнить всю необходимую информацию и показать их в своих представлениях (контроллер курса будет диктовать). Надеюсь, это поможет.

Ответ 6

На самом деле не так уж сложно повторять проверки в нескольких слоях (на стороне клиента, на стороне сервера в контроллере или в эквиваленте и снова на бизнес-уровне). Это делает ваш код несколько отключенным. В идеале вам нужно было бы описать их только в одном месте, но иногда это невозможно. Если вы не используете аннотации данных, неужели вы делаете это очень тяжело для себя, если хотите выполнить проверку на стороне клиента? Кажется, так.

В любом случае, то, что я делал в прошлом в приложениях, отличных от mvc, имеет большинство методов действий, возвращающих объект Response, который включает в себя статус (успех, ошибки, предупреждения) и список ошибок проверки, а также любые другие требуемые свойства.

Возможно, вы сможете использовать интерфейс IValidateableObject, но это еще раз связывает вас с чем-то специфичным для ASP.net. Возможно, компромисс будет заключаться в том, чтобы потреблять ваш объект ответа и преобразовывать его в ошибки, связанные с DataAnnotation.