Лучшее место для Свободной конфигурации IOC/Модулей (в настоящее время пытается Ninject)
Я изо всех сил стараюсь найти наилучшее место для размещения моей конфигурации Ninject "Модули" (место, где указаны привязки типов). Надеюсь, что я просто пропустил какой-то очевидный трюк, так как это начинает превращаться в развязку для меня с использованием свободной конфигурации (и, следовательно, Ninject):
В простой веб-стек, содержащий три отдельных проекта: Web, BusinessLogic, DataAccess. Я не хочу, чтобы веб-уровень должен был напрямую ссылаться на уровень DataAccess, но я не вижу способа обойти это, потому что:
-
Если я поставлю модуль конфигурации DataAccess на уровне DataAccess, мне нужно ссылаться на уровень DataAccess, чтобы я мог получить доступ к модулю конфигурации при создании экземпляра ядра Ninject в уровне веб-сайта
-
Если я поместил модуль конфигурации DataAccess в уровень веб-сайта, мне нужно ссылаться на уровень DataAccess, чтобы получить доступ к типам, которые я хочу связать
-
Если я поместил модуль конфигурации DataAccess в отдельный проект конфигурации, я получаю круговые проблемы с ссылкой при попытке указать привязки для уровней как в Интернете, так и в DataAccess.
/li >
Часть преимуществ IOC заключается в том, чтобы разрешить свободное соединение, но, насколько я вижу, использование Ninject потребует от меня добавления более прямых ссылок на проекты, которые у меня есть. Что мне не хватает?
Ответы
Ответ 1
Ninject не требует ссылки на сборки! Вы можете указать Kernel
загрузить все модули из сборок, которые соответствуют определенному шаблону - см. Перегрузки Load()
! Используя этот механизм, вы можете отобразить свои объекты как модули, как @Daniel Marbach, предлагаемые в том месте, где реализована каждая функция. Мне не нравятся эти огромные модули, определяющие каждую привязку для сборки. Я бы предпочел, чтобы каждый из них в определенном небольшом модуле для определенной функции.
Это также позволяет включать/отключать/заменять реализации без перекомпиляции других сборок (по крайней мере, если у вас есть интерфейсы в отдельных сборках).
Итак, в основном у вас есть:
- Одна или несколько узлов веб-уровня: содержат контроллеры, представления и привязки для веб-уровня. Каждая из сборок ссылается на некоторые сборки, которые определяют интерфейсы, от которых он зависит.
- Одна или несколько сборок, которые определяют интерфейсы для зависимостей веб-уровня.
- Одна или несколько сборок бизнес-логики, реализующих все или некоторые интерфейсы, требуемые веб-уровнем. Ссылка на некоторые сборки, которые содержат интерфейсы объектов, от которых они зависят. Содержит модули, которые определяют привязки для компонентов, которые они предоставляют.
- Одна или несколько сборок, которые определяют интерфейсы для зависимостей уровня бизнес-логики.
- Одна или несколько сборок, которые реализуют зависимости уровня бизнес-логики и, возможно, некоторого веб-уровня (например, данные, которые напрямую предоставляются с бизнес-логикой). Содержит модули компонентов, которые они предоставляют.
- Один загрузочный загрузчик загружает модули этих сборок с помощью
kernel.Load("*.dll")
или подобных.
Преимущество этого:
- Нет ссылок от веб-уровня на уровень бизнес-логики и уровень данных
- Нет ссылки с уровня бизнес-логики на уровень данных
- Каждый слой может быть заменен без какого-либо воздействия на других.
Ответ 2
Я обычно создаю сборку только для контейнера и конфигурации IOC; Затем эта Ассамблея может ссылаться на все другие сборки и Ninject (или StructureMap в моем случае). Затем веб-приложение просто должно ссылаться на сборку IOC и включать пару строк кода инициализации, которые непосредственно используют сборку IOC.
Однако одно примечание - сборка MyOC не ссылается на веб-сборку (которая вводит циклическую ссылку). Все, что нужно вводить, определяется за пределами веб-сборки, поэтому это меня не беспокоит.
Ответ 3
Лучший способ организовать ваши модули - это функция! Например
- AuthenticationModule
- OrderModule
- CustomerModule
Удачи!
Ответ 4
Я всегда добавлял конфигурацию Ninject Modules в отдельную сборку, такую как Acme.Common, и ссылаюсь на это с Acme.Data, Acme.Domain и т.д., поэтому нет круговых зависимостей, я всегда могу заменить Acme.Common после некоторых изменений в регистрации без проблемы.