ASP.NET MVC - должна ли бизнес-логика существовать в контроллерах?

97

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

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

Кевин Панг
источник
Ссылка на статью мертва - web.archive.org/web/20150906064521/http://devlicio.us/blogs/… является копией с archive.org для всех, кто интересуется.
Стюарт Мур

Ответы:

75

Бизнес-логика действительно должна быть в модели. Вы должны стремиться к толстым моделям, худым контроллерам.

Например, вместо:

public interface IOrderService{
    int CalculateTotal(Order order);
}

Я бы предпочел:

public class Order{
    int CalculateTotal(ITaxService service){...}        
}

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

Это сделает ваш контроллер примерно таким:

public class OrdersController{
    public OrdersController(ITaxService taxService, IOrdersRepository ordersRepository){...}

    public void Show(int id){
        ViewData["OrderTotal"] = ordersRepository.LoadOrder(id).CalculateTotal(taxService);
    }
}

Или что-то вроде того.

Джонни
источник
1
Итак, вы бы ввели службы в свои контроллеры вместо репозиториев? Как в этом случае вступает в силу принцип единицы работы?
Кевин Пан,
Я написал еще кое-что, надеюсь, это имеет больше смысла. Вы также можете прочитать: weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model. Несмотря на то, что он касается Rails, он все еще очень применим.
jonnii,
Я бы лично назвал репозиторий услугой.
Брэд Уилсон,
Это определенно своего рода служба, но специально для доступа к данным. Это просто условность, которую я использую, а не то, что я конкретно защищаю.
jonnii
1
Это сделает вашу модель тесно связанной с ITaxService. Если вы хотите повторно использовать модель в другом проекте или другой DLL, у вас должна быть реализация ITaxService или ссылка, иначе ваша модель будет сломана, что приведет к нарушению принципов SOLID. ITaxService должен иметь ссылку на вашу модель. Таким образом, вы можете повторно использовать свою модель в другом проекте без ссылки на ITaxService.
Мехмет Али Серт
65

Мне нравится диаграмма, представленная Microsoft Patterns & Practices . И я верю в пословицу: «Картинка стоит тысячи слов».

На диаграмме показана архитектура уровней MVC и бизнес-сервисов.

AlejandroR
источник
6
Это действительно полезно! Не могли бы вы сказать мне, где на том сайте вы нашли эту диаграмму?
Роб Черч
2
Это из «Реализации на стороне сервера» Microsoft msdn.microsoft.com/en-us/library/hh404093.aspx
Джастин
Хорошо, но, скажем, в приложении MVC - куда идет бизнес-логика? Кажется, нам нужен дополнительный сервисный слой или что-то в этом роде ?!
niico 09
14

Это интересный вопрос.

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

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

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

Джо Несущий души
источник
14

Вы можете проверить это замечательное руководство Стивена Вальтера, в котором показана проверка с помощью уровня обслуживания .

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

Лениэль Маккаферри
источник
2
Это самый правильный ответ. Я лично выступаю за то, чтобы не предоставлять сервисы контроллеру, а вместо этого использовать концепцию ViewModel, такую ​​как шаблон MVVM. Представьте себе сценарий, в котором вы хотите написать бизнес-приложение с интерфейсом рабочего стола (скажем, формы Windows или WPF), а также с веб-интерфейсом. Решение этой проблемы приводит вас к паттерну «тонкий контроллер», который также предлагается здесь. Итог: никогда не помещайте бизнес-логику в модель или контроллер и не помещайте в контроллер ничего, чего у вас нет.
Сэм
9

Бизнес-логика не должна содержаться в контроллерах. Контроллеры должны быть максимально тонкими, в идеале следовать скороговорке:

  1. Найти объект домена
  2. Действовать на объект домена
  3. Подготовить данные для просмотра / возврата результатов

Дополнительно контроллеры могут содержать некоторую логику приложения.

Так где же мне разместить свою бизнес-логику? В модели.

Что такое модель? Это хороший вопрос. См. Статью Microsoft Patterns and Practices (слава AlejandroR за отличный поиск). Здесь есть три категории моделей:

  • Модель представления : это просто пакет данных с минимальной логикой, если таковая имеется, для передачи данных из представлений и в представления, содержит базовую проверку полей.
  • Модель предметной области : жирная модель с бизнес-логикой, работает с одним или несколькими объектами данных (то есть с объектом A в данном состоянии, а не с объектом B).
  • Модель данных : модель с учетом хранения, логика, содержащаяся в одном объекте, относится только к этому объекту (т.е. если поле a, то поле b)

Конечно, MVC - это парадигма, которая бывает разных видов. Здесь я описываю MVC, занимающий только верхний уровень, см. Эту статью в Википедии.

Сегодня MVC и аналогичные модели-представления-презентаторы (MVP) представляют собой шаблоны проектирования «Разделение проблем», которые применяются исключительно к уровню представления более крупной системы. В простых сценариях MVC может представлять первичный дизайн системы, обращаясь непосредственно к базе данных; однако в большинстве сценариев Контроллер и Модель в MVC слабо зависят от уровня / уровня службы или данных. Это все об архитектуре клиент-сервер

Яцек Глен
источник
-1

Если вы используете инжекторы зависимостей, ваша бизнес-логика перейдет к ним, и, следовательно, вы получите аккуратные и чистые контроллеры.

Чандреш Пател
источник