У меня есть приложение, которое разрабатывается в соответствии с модульным дизайном приложения. Существует «базовый» вертикальный стек, который обеспечивает общие центральные службы, такие как аутентификация / авторизация, ведение журнала, доступ к данным и т. Д. Контекстные области реализованы в модулях, которые ссылаются на базовую сборку на одном и том же логическом уровне.
Приложение представляет собой сервисное приложение с фасадным уровнем, доменным уровнем и кодом инфраструктуры, содержащим код доступа к данным. Каждый модуль будет реализовывать сборку на уровне домена. Если у модуля есть открытый API, он также реализует сборку фасада.
Например, решение содержит:
Core.Api - Фасадная сборка для основного API
Core - сборка домена для основных служб, объектов и т. Д.
Core.Data - сборка доступа к данным ядра
ModuleA.Api - Фасадная сборка для модуля A (ссылки Core.Api)
Модуль A - Сборка домена для модуля A (ссылается на Core)
ModuleB.Api - Фасадная сборка для модуля B (ссылки Core.Api)
ModuleB - Сборка домена для модуля B (ссылается на Core)
(и т. Д. Когда закончим, у нас будет около 24 модулей.)
Все это связано с использованием DI с Unity в качестве контейнера IoC. Проект WebHost определяет конфигурацию, в которой различные реализации сопоставляются с интерфейсами, которые они заполняют.
Этот подход не просто для логических целей, но для обеспечения гибкости в реализации (т. Е. Мы можем изменить реализацию модуля, не нарушая или даже не касаясь другого кода). Это также делает чрезвычайно легким разделение работы между группами и расширение приложения новыми модулями с небольшим риском ошибки регрессии в другом коде.
Мой вопрос заключается в том, что делать, если для ModuleB требуется один или несколько типов, определенных в ModuleA? Допустимо ли для ModuleB ссылаться на ModuleA или мне нужно переместить ModuleA в ядро?
UPDATE
Рассматривая реализацию некоторых из рассмотренных ниже изменений, я столкнулся с ошибкой, которая приводит меня к этому разъяснению ...
Есть два места, где мои модули взаимозависимы. Следуя подходу, обсуждаемому ниже, я могу переместить интерфейсы и типы, которые я хочу использовать совместно, из Module1 в Core, что позволяет ModuleB использовать их без тесной связи между ModuleA и ModuleB. Однако мне также необходимо использовать некоторые из контрактов данных, определенных в ModuleA.Api, для операций сервиса в ModuleB.Api. Это заставляет меня сомневаться в дизайне.
Из-за IP я не могу описать наш точный вариант использования, но достаточно сказать, что ModuleA имеет объект домена EntityA. ModuleA.Api определяет контракт данных EntityContractA (DTO), предоставляемый общедоступным API. ModuleB.Api имеет метод, который требует EntityContractA в качестве параметра, а затем делегирует метод в ModuleB, который принимает EntityA в качестве параметра.
Опять же, перемещение EntityA в Core решает проблему доменного уровня, но не помогает мне с фасадным слоем. Перемещение EntityContractA в Core.Api немного пахнет.
Вот пример того, что мне нужно сделать:
В ModuleB.Api.ServiceFacadeB:
public EntityContractB FilterBy(EntityContractA contractA)
{
var entityA = Mapper.Map<EntityContractA, EntityA>(contractA);
var entityB = domainService.FilterBy(entityA);
var contractB = Mapper.Map<EntityB, EntityContractB>(entityB);
return contractB;
}
, где domainService - это ModuleA.ServiceB:
public EntityB FilterBy(EntityA entityA)
{
// Do work
}