Мнение о архитектуре ASP.NET MVC Onion
Каково ваше мнение о следующей "общей" кодовой первой архитектуре ASP.NET MVC, разработанной Onion:
![screenshot of the solution explorer]()
Слои, объясненные:
Core - содержит модель домена. например что бизнес-объекты и их отношения. Я использую Entity Framework для визуального проектирования объектов и отношений между ними. Это позволяет мне генерировать script для базы данных. Я получаю автоматически созданные POCO-подобные модели, на которые я могу свободно ссылаться на следующем уровне (Persistence), поскольку они просты (т.е. Они не зависят от базы данных).
Персистирование - интерфейс и реализации репозитория. В основном операции CRUD в модели домена.
BusinessServices - бизнес-уровень вокруг репозитория. Вся бизнес-логика должна быть здесь (например, GetLargestTeam()
и т.д.). Использует операции CRUD для создания возвращаемых объектов или получения/фильтрации/хранения данных. Должны содержать все бизнес-правила и проверки.
Веб (или любой другой пользовательский интерфейс). В этом конкретном случае это приложение MVC, но идея этого проекта заключается в предоставлении пользовательского интерфейса, основанного на том, что предлагают бизнес-услуги. Проект пользовательского интерфейса потребляет бизнес-уровень и не имеет прямого доступа к репозиторию. Проект MVC имеет свои собственные модели просмотра, которые являются специфическими для каждой ситуации просмотра. Я не пытаюсь принудительно подавать его в доменные модели.
Итак, ссылки выглядят так:
UI → Бизнес-услуги → Репозиторий → Основные объекты
Что мне нравится:
- Я могу конструировать свои объекты, а не закодировать их вручную. я осознаю
созданных кодом объектов Model.
- Пользовательский интерфейс управляется/выполняется
слой. Различные приложения пользовательского интерфейса могут быть закодированы против того же
Бизнес-модель.
Смешанные чувства о:
- Хорошо, у нас есть реалистичная реализация репозитория, но как часто у вас действительно разные реализации одного и того же интерфейса настойчивости?
- То же самое касается интерфейса - у нас есть технические возможности для реализации различных приложений пользовательского интерфейса по тем же бизнес-правилам, но зачем нам это делать, когда мы можем просто визуализировать разные виды (мобильные, настольные и т.д.)?
- Я не уверен, что пользовательский интерфейс должен только взаимодействовать с бизнес-слоем через модели просмотра, или я должен использовать модели доменов для передачи данных, как и сейчас. Для отображения я использую модели просмотра, но для передачи данных я использую модели домена. Неправильно?
Что мне не нравится:
- Проект Core теперь ссылается во всех других проектах - потому что я хочу/должен получить доступ к моделям Домен. В классической архитектуре лука на ядре ссылается только следующий слой.
- DbContext реализован в проекте .Core, поскольку он генерируется Entity Framework в том же месте, где находится .edmx. Я действительно хочу использовать .EDMX для визуального моделирования модели, но я чувствую, что DbContext принадлежит к слою Persistence, где-то внутри реализации репозитория конкретной базы данных.
В качестве окончательного вопроса - что такое хорошая архитектура, которая не слишком переработана (например, полноразмерный лук, где у нас есть инъекции, локаторы сервисов и т.д.), но в то же время обеспечивает некоторую разумную гибкость, в местах где вам это реально нужно?
Спасибо
Ответы
Ответ 1
Ничего себе, здесь многое сказать!; -)
Прежде всего, давайте поговорим об общей архитектуре.
То, что я вижу здесь, это то, что на самом деле это не лунная архитектура. Вы забыли внешний слой, слой "Разрешение зависимостей". В архитектуре Onion, вплоть до этого уровня, для подключения основных интерфейсов к реализации инфраструктуры (где должен находиться ваш проект Persistence).
Вот краткое описание того, что вы должны найти в приложении "Лук". Что касается уровня Core, все это уникально для бизнеса: модель домена, бизнес-процессы... Этот уровень определяет все потребности в технической реализации в качестве интерфейсов (например: интерфейсы репозиториев, интерфейсы ведения журнала, интерфейсы сеансов...). Уровень ядра не может ссылаться на любые внешние библиотеки и не имеет специального кода для конкретной технологии. Второй уровень - это уровень инфраструктуры. Этот уровень обеспечивает реализацию для не-бизнес-интерфейсов Core. Здесь вы вызываете свою БД, свои веб-службы... Вы можете ссылаться на любые внешние библиотеки, которые вам нужны для обеспечения реализаций, развертывать столько пакетов самородок, сколько хотите:-). Третий уровень - это ваш пользовательский интерфейс, ну, вы знаете, что добавить туда;-) И последний уровень, его разрешение зависимостей, о котором я говорил выше.
Направление зависимости между слоями относится к центру.
Вот как это могло бы выглядеть:
![Onion App Structure]()
Теперь возникает вопрос: как подогнать то, что вы уже закодировали в архитектуре лука.
Ядро: содержит модель домена
Да, это подходящее место!
Стойкость - интерфейс и реализации репозитория
Ну, вам нужно разделить интерфейсы с реализациями. Интерфейсы необходимо перенести в Core, а реализации необходимо перенести в папку Infrastructure (вы можете назвать этот проект Persistence).
BusinessServices - бизнес-уровень вокруг репозитория. Все бизнес-логика должна быть здесь
Это нужно перенести в Core, но здесь вы не должны использовать реализации репозиториев, просто манипулируйте интерфейсами!
Web (или любой другой пользовательский интерфейс). В этом конкретном случае это MVC Приложение
cool: -)
Вам нужно добавить проект "Bootstrapper", просто посмотрите здесь, чтобы узнать, как продолжить.
О ваших смешанных чувствах:
Я не буду обсуждать необходимость наличия репозиториев или нет, вы найдете много ответов на stackoverflow.
В моем проекте ViewModel у меня есть папка под названием "Builder". Его до моих Строителей обсуждать с моими интерфейсами бизнес-сервисов для получения данных. Строитель получит списки объектов Core.Domain и отобразит их в правую ViewModel.
О том, что вам не нравится:
В классической архитектуре лука на ядре ссылаются только следующие слой.
Ложь!:-) Каждому слою требуется, чтобы Core имел доступ ко всем интерфейсам, определенным там.
DbContext реализован в проекте .Core, поскольку он созданный платформой Entity Framework, в том же месте, где .edmx это
Еще раз, это не проблема, как только ее очень легко редактировать шаблон T4, связанный с вашим EDMX. Вам просто нужно изменить путь к сгенерированным файлам, и вы можете иметь EDMX на уровне инфраструктуры и POCOs в вашем проекте Core.Domain.
Надеюсь, это поможет!
Ответ 2
Я ввожу свои службы в свои контроллеры. Службы возвращают DTO, которые находятся в Core.
Модель у вас хорошо выглядит, я не использую шаблон репозитория, но многие люди делают это. Мне сложно работать с EF в этом типе архитектуры, поэтому я решил использовать Nhibernate.
Возможный ответ на ваш последний вопрос.
- CORE
- DOMAIN
- DI
- ИНФРАСТРУКТУРА
- ПРЕЗЕНТАЦИЯ
- УСЛУГИ
Ответ 3
По-моему:
- "В классической архитектуре лука на ядре ссылается только следующий слой".
Это не так, Core должен быть ссылкой любым слоем... помните, что Направление зависимости между слоями относится к центру (Core).
![enter image description here]()
"слои выше могут использовать любой слой под ними". Джеффри Палермо http://jeffreypalermo.com/blog/the-onion-architecture-part-3/
- О вашем EF, он находится в неправильном месте.... он должен быть в слое Infrastructure не на уровне Core. И используйте POCO Generator для создания сущностей (классы POCO) в Core/Model. Или используйте Auto-mapper, чтобы вы могли сопоставить Core Model (Бизнес-объекты) с Entity Model (EF Entities)
В другой руке я создал простое приложение с использованием Onion Architecture, чтобы показать зависимости между уровнями и способы их реализации.
http://www.jaider.net/posts/935-onion-architecture-in-action-get-started/
![enter image description here]()
Ответ 4
То, что вы сделали, выглядит довольно хорошо и в основном является одной из двух стандартных архитектур, которые я вижу много.
Смешанные чувства о:
Хорошо, у нас есть реалистичная реализация репозитория, но как часто у вас действительно разные реализации одного и того же интерфейса персистентности?
Pluggable часто рекламируется как хороший дизайн, но я ни разу не видел, как команда меняет основную реализацию чего-то для чего-то другого. Они просто изменяют существующее. IMHO "подключаемость" полезна только для того, чтобы быть в состоянии издеваться над компонентами для автоматизированных модульных испытаний.
Я не уверен, что пользовательский интерфейс должен только взаимодействовать с бизнес-слоем через модели просмотра или использовать модели домена для передачи данных, как и сейчас. Для отображения я использую модели просмотра, но для передачи данных я использую модели домена. Неправильно?
Я считаю, что модели просмотра представляют собой проблему с интерфейсом UI (MVC Web), если вы добавили другой тип пользовательского интерфейса, например, он может не потребовать просмотра моделей или может потребоваться что-то другое. Поэтому я думаю, что бизнес-уровень должен возвращать объекты домена и разрешать их сопоставление для просмотра моделей в слое пользовательского интерфейса.
Что мне не нравится:
Проект Core теперь ссылается на каждый другой проект - потому что я хочу/должен получить доступ к моделям Домен. В классической архитектуре лука на ядре ссылается только следующий слой.
Как говорили другие, это вполне нормально. Обычно все заканчивается тем, что имеет зависимость от Домена.
DbContext реализуется в проекте .Core, потому что он генерируется платформой Entity Framework в том же месте, где находится .edmx. Я действительно хочу использовать .EDMX для визуального моделирования модели, но я чувствую, что DbContext относится к уровню Persistence, где-то в реализации репозитория конкретной базы данных.
Я думаю, что это является следствием Entity Framework. Если вы использовали его в режиме "Первый код", вы фактически можете - и обычно - иметь контекст и репозиторий на уровне Persistance с Доменом (представленным как классы POCO) в том, что вы назвали Core.
В качестве окончательного вопроса - что такое хорошая архитектура, которая не слишком переработана (например, полноразмерный лук, где у нас есть инъекции, локаторы сервисов и т.д.), но в то же время обеспечивает некоторую разумную гибкость, в местах где вам это реально нужно?
Как я коснулся выше, я не стал бы беспокоиться о необходимости замены вещей, кроме как для автоматических модульных тестов. Если не существует конкретного требования, о котором вы знаете, это очень вероятно.
Удачи!