Внедрение зависимостей в луковичной архитектуре для. NET Core - PullRequest
0 голосов
/ 02 апреля 2020

Я пытаюсь реализовать луковую архитектуру в. NET Core 3.1 проекте веб-API с EntityFramework в качестве ORM.

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

Допустим, у нас есть следующие кольца (от внешнего к внутреннему):

  • Инфраструктура (API, постоянство)
  • Приложение ( Службы)
  • Домен (Модели + Доменные службы)

Из того, что я понимаю в луковой архитектуре, отдельные проблемы на одном уровне не должны зависеть друг от друга. Поэтому в кольце инфраструктуры, а точнее в проекте API, я понимаю, как подключить DI для моих сервисов, поскольку эти сервисы (интерфейсы и реализации) находятся в нижних кольцах. Однако мне также нужно настроить DI для моего DbContext, который определен в проекте Persistence того же кольца. Кроме того, через DI необходимо подключить дополнительные сторонние инструменты, которые также будут находиться в том же кольце.

Есть два решения, которые я вижу для этого:

  1. Сделать Проект API зависит от проекта Persistence (и от дополнительных сторонних проектов). Это нарушает правила луковой архитектуры, как я понимаю.
  2. Разделите кольцо инфраструктуры на два кольца, где нижняя половина будет содержать веб-API, постоянство и любые дополнительные проекты, но верхняя половина будет выделенным слоем DI, который настроит все Д.И. Я считаю, что этот внешний слой называется композицией root.

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

Ответы [ 2 ]

1 голос
/ 02 апреля 2020

Вот мое понимание:

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

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

Композиция root затем настраивает приложение так, чтобы конкретные реализации соответствовали абстракциям, определенным в домене. Это конфигурация DI.

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

  • Реализация зависимостей также может быть автономной, как в области. Еще один проект адаптирует их к интерфейсам домена. Таким образом, ваши репозитории не будут напрямую реализовывать доменные интерфейсы.
  • Конфигурация абстракций домена - сопоставление их с их конкретными зависимостями - может быть разделена. Другими словами, настройки вашего контейнера могут быть отделены от хоста приложения. В идеале хост приложения должен нести ответственность за чтение значений своей конфигурации или среды и передачу их в эту конфигурацию контейнера. Это предотвращает соединение конфигурации контейнера с такими деталями, как JSON или .config. Это проще для тестирования.

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


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

API подобен противоположности домена. Домен ни от чего не зависит. Другие зависимости указывают внутрь. Репозитории, например, реализуют абстракции, определенные доменом.

API, с другой стороны, в конечном итоге зависит от всего. Он использует конфигурацию DI для предоставления зависимостей (таких как постоянство) в домен, что означает, что он будет зависеть от всех из них.


Вот (на мой взгляд) самое большое изменение в мышлении:

У нас есть тенденция писать конкретные классы для доступа к данным, вызывать внешние API и делать другие вещи, которые являются периферийными по отношению к домену. Затем мы помещаем интерфейсы на них. Эти интерфейсы часто выглядят как запоздалая мысль. Как будто мы просто создаем интерфейсы, которые отражают эти классы. Если мы добавим что-то в класс, мы добавим это в интерфейс.

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

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

У нас все еще может быть универсальный c универсальный репозиторий. Это нормально. Но мы адаптируем его к интерфейсу хранилища доменов. Домен не знает об этом. Все, что он знает, - это абстракция, определенная в домене. Класс предметной области зависит от небольших разделенных абстракций, которые он определяет для своих собственных целей. Он владеет ими. Это делает его простым и делает его действительно простым для тестирования.

0 голосов
/ 04 апреля 2020

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

В дополнение к моему проекту API я также создал проект DI. Этот проект DI является проектом root. Он зависит от всего (приложения, домена и т. Д. c). Это верхняя часть (внешнее подкольцо) кольца инфраструктуры. Затем в моем проекте API я ссылаюсь на проект DI и вызываю оттуда метод расширения, чтобы t ie перевести все мои контракты в реализации. Кроме того, мне пришлось добавить второе веб-приложение для чего-то другого, как часть этого же решения, и я смог использовать тот же метод, что хорошо.

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