MVC 3 - Контроллеры и ViewModels - Что должно содержать большую часть бизнес-логики?
В настоящее время в моем приложении и использовании шаблона работы и общего репозитория все мои контроллеры содержат всю бизнес-логику. Я пытаюсь использовать все возможности ViewModels вместо прямой модели.
Хотя это хорошая идея, теперь возникает вопрос, который может значительно отделить мою бизнес-логику в контроллерах. Для контроллеров и ViewModels, которые должны содержать большую часть бизнес-логики?
Я пробовал несколько способов заставить мои ViewModels практически содержать всю бизнес-логику. Тем не менее, мне нужно иметь аргумент в моем конструкторе ViewModel, который принимает подразделение работы. Это хорошая идея?
Мой запах кода говорит мне об этом. Тем не менее, я просто немного обеспокоен тем, как это будет согласовано с контроллерами, которые выполняют действия, не требующие ViewModels. Проще говоря, действия, которые не требуют передачи модели /ViewModel в представление; этот случай происходит при действиях, которые перенаправляются на другие действия. Это означает, что моя бизнес-логика может либо остаться в этом действии, либо я могу отделить эту бизнес-логику от функции.
Какая здесь самая лучшая практика?
Ответы
Ответ 1
Для контроллеров и ViewModels, которые должны содержать большую часть бизнес-логики?
Ни один из них.
Я пробовал несколько способов заставить мои ViewModels практически содержать всю бизнес-логику. Тем не менее, мне нужно иметь аргумент в моем конструкторе ViewModel, который принимает подразделение работы. Это хорошая идея?
imho Это очень плохая идея. Прежде всего, вы нарушаете несколько принципов SOLID. Объединение всего кода в модель просмотра затрудняет тестирование. Что делать, если вы хотите использовать некоторые бизнес-логики в другом представлении? Вы дублируете этот код?
Какая здесь самая лучшая практика?
Сначала вернитесь к шаблону MVC. Это довольно широкое определение, но знание этого должно дать вам ощущение того, что вы должны разместить там.
-
"Модель" в MVC - это все, что используется для сбора данных вместе. Это могут быть веб-сервисы, бизнес-уровень, репозитории и т.д.
-
Представление - это весь код, который генерирует HTML (поскольку мы говорим о сети).
-
Контроллер должен рассматриваться как клей между моделью и представлением. Следовательно, он должен взять информацию из Модели и преобразовать ее во что-то, что можно использовать в представлении.
Проблема с этой структурой заключается в том, что довольно легко "утекать" информацию о конкретном слое в другие части шаблона. Следовательно, Microsoft представила ViewModels в их реализацию MVC.
Таким образом, мы можем удалить всю визуализацию из представлений и поместить ее в ViewModel. Вместо этого в вашем представлении:
<span>@(model.Age == 0 ? "n/a" : model.Age)</span>
вы помещаете этот код внутри ViewModel и просто вызываете @model.Age
. Таким образом, вам не нужно дублировать этот код во всех представлениях, которые используют вашу модель представления.
Ответ на ваш вопрос о ViewModel заключается в том, что он должен содержать только логику, которая используется для правильного отображения информации из "Модели".
Что касается контроллера, я бы тоже не вложил в него никакой бизнес-логики. Прежде всего, это очень сложно проверить вашу логику. Затем вы добавляете к нему дополнительные обязанности (и тем самым прерывая SRP). Единственная логика, которая действительна в контроллере, - это получить информацию из ViewModel и преобразовать ее в нечто, используемое "Моделью" и наоборот.
Надеюсь, что ответит на ваш вопрос.
Обновление
Я бы создал отдельный проект и добавил к нему классы. Затем просто добавьте ссылку из своего веб-проекта и вызовите эти классы в контроллерах.
Я бы также начал использовать инверсию контейнера управления, чтобы автоматически создавать эти зависимости, созданные для меня.
Autofac может как открыть ваши сервисы для вас (нуль-конфигурация), так и внедрить себя в MVC.
Чтобы следовать шаблону разделенного интерфейса, создайте следующие проекты:
- YourProject.BusinessLayer < - Добавьте сюда свои классы.
- YourProject.BusinessLayer.Specification < - Добавьте интерфейсы, которые определяют ваш бизнес-уровень здесь.
- YourProject.Mvc < - проект MVC.
Проект "Спецификация" может использоваться для упрощения тестирования и упрощения переключения реализации (может быть, всего несколько классов, а не только весь бизнес-уровень). Прочитайте "Шаблон разделенного интерфейса"
Ответ 2
Я не могу сказать, что мой подход - лучшая практика, но я предпочитаю помещать любую бизнес-логику в отдельный слой "службы".
Я стараюсь использовать ViewModel только для хранения свойств, необходимых для определенного вида. Если в ViewModel есть какие-либо методы, они скорее всего будут извлекать коллекции, связанные с этим представлением.
Я держу свои контроллеры легкими, пытаясь ограничить их проверкой и перенаправлением/отображением просмотров как можно больше.
Итак, если у меня есть сложная логика, у меня будет вызов действия контроллера для отдельной службы, чтобы обработать эту логику. Таким образом, логика изолирована, что упрощает тестирование, так как больше нет необходимости создавать контроллер или ViewModel для его проверки. Это также облегчает повторное использование сервиса, чем выделение ViewModel.
Надеюсь, это поможет. Удачи.
Ответ 3
Model-View-View Model (MVVM) - это шаблон проектирования для создания пользовательских интерфейсов. Ваша модель просмотра представляет собой чистое представление данных и операций в пользовательском интерфейсе. Таким образом, он должен содержать логику, связанную с этим интерфейсом.
Например:
Если вы создаете редактор списка, ваша модель представления будет объектом, содержащим список элементов, и выставляя методы для добавления и удаления элементов.
Из Википедии:
ViewModel: ViewModel - это "Модель представления", означающая, что это абстракция представления, которая также служит для связывания данных между Просмотр и модель. Это можно рассматривать как специализированный аспект того, что будет Controller (в шаблоне MVC), который действует как данные связующий/конвертер, который изменяет информацию о модели в View information и передает команды из представления в модель. ViewModel раскрывает публичные свойства, команды и абстракции. ViewModel сравнивается с концептуальным состоянием данных, в отличие от реальное состояние данных в модели. [7]
Ответ 4
ваш контроллер вызовет UoW, чтобы получить данные, необходимые для создания вашей модели просмотра.
вы можете вызвать более 1 метода своего UoW
то вы передаете все необходимые данные вашему конструктору viewmodel. (передача Uow в viewmodel звучит как очень плохо)
Если вам нужна сложная "логика" на вашем контроллере, вызывающая множество методов из UoW и т.д., вы должны подумать о создании другого репозитория или только уровня бизнес-логики, который выполняет всю тяжелую работу, и вы вызываете ее с вашего контроллера, например
SomeClass something = Uow.BLGoodName.DoSomeFancyStuff(params ..)
ViewData.model = new ControllerActionViewModel(something);
Return View();