Проверка MVC - СУХОЙ с уровнем обслуживания - Какова лучшая практика? - PullRequest
15 голосов
/ 10 ноября 2011

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

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

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

У меня было несколько идей, но все они не были правильными.Я чувствую, что ответ включает в себя сущности модели представления, но это приводит к целой проблеме сопоставления, которая должна быть решена, не говоря уже о том, что это нарушает принцип СУХОЙ (не повторяйся).Что такое лучшая практика?

Ответы [ 6 ]

17 голосов
/ 10 ноября 2011

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

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

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

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

6 голосов
/ 10 ноября 2011

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

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

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

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

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

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

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

Тогда модели DTO / представления могутнаходиться в слое MVC, и вы можете украсить их с помощью атрибутов проверки и иметьntroller передает их представлениям - таким образом, используя встроенную проверку MVC.

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

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

4 голосов
/ 10 ноября 2011

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

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

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

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

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

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

Удачи!

2 голосов
/ 10 ноября 2011

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

Был использован следующий подход:

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

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

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

1 голос
/ 30 августа 2012

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

0 голосов
/ 06 июня 2012

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...