Следует ли абстрагировать конфигурацию контейнера IOC от пользовательского интерфейса?

Наша команда создала приложение DDD, которое имеет четко определенный уровень сервисов приложений, построенный как «API» системы. Он объединяет все, начиная с домена и инфраструктуры, для выполнения общих задач. В качестве ввода / вывода он не использует ничего, кроме DTO, поэтому домен никогда не выходит за пределы этого уровня.

Теперь мы хотим добавить в микс контейнер для внедрения зависимостей и столкнулись с некоторыми трудностями. У нас есть два клиентских приложения, которые используют службы приложений для выполнения своей работы: приложение MVC 2 и приложение службы Windows. Традиционно весь код конфигурации для работы с внедрением зависимостей помещается в файл global.asax в проекте mvc, чему я видел множество примеров. Проблема в том, что регистрационный код IOC затем дублируется в службе Windows и немного изменяется для этой платформы.

У меня проблема в том, что DI требует, чтобы клиентское приложение знало, что и как регистрировать, что также требует, чтобы клиентское приложение имело ссылки на уровни домена и инфраструктуры. Вся идея создания уровня сервисов приложений заключалась в том, что это единственное, о чем клиенты должны знать и с чем разговаривать. Мое предложенное решение состояло в том, чтобы создать «Службу зависимостей» на уровне службы моего приложения, которую клиенты будут вызывать один раз, и она будет настраивать контейнер DI, поскольку он знает, что требуется. У него также будут методы, позволяющие клиентскому приложению регистрировать собственные дополнительные зависимости. Например, проект MVC зарегистрирует свою фабрику контроллеров, а служба Windows зарегистрирует свой класс запуска. Я хотел знать, необычно ли это или я ошибаюсь с этой идеей. Кто-нибудь еще сталкивался с этой проблемой раньше?




Ответы (2)


Есть много способов снять шкуру с кошки; Однако похоже, что вы принимаете неправильный подход. Точка входа приложения (Global.asax или Program.cs) обязательно должна быть местом, где выбираются компоненты для настройки в контейнере IoC. С другой стороны, ваши сервисы, как правило, не должны иметь встроенных знаний о конфигурации IoC. Я предполагаю, что вы уже следуете этому принципу, но пересматриваете его из-за повторяющейся конфигурации.

Чтобы сделать это возможным без повторения кода, как вы описали, многие контейнеры IoC предоставляют конструкции модуляризации, которые инкапсулируют конфигурацию набора связанных компонентов. В Autofac (и Ninject IIRC) они называются «модулями» - http://code.google.com/p/autofac/wiki/StructuringWithModules. Castle Windsor называет их «установщиками», в то время как StructureMap называет их «реестрами».

За счет разложения конфигурации на модули объем кода конфигурации в методе запуска приложения сокращается. В вашем примере для упрощения вы можете создать три модуля:

  • CoreModule
  • WebModule
  • ServiceProcessModule

CoreModule будет содержать конфигурацию для общих компонентов, которые ведут себя одинаково в каждой из сред выполнения.

WebModule и ServiceProcessModule будут содержать регистрации для компонентов, специфичных для этих сред, а также специализированную конфигурацию любых общих компонентов, которые настраиваются по-разному в зависимости от хоста.

Тогда запуск вашего веб-приложения будет примерно таким:

foo.RegisterModule<CoreModule>();
foo.RegisterModule<WebModule>();
// Resolve root component, run app

Хотя процесс обслуживания будет очень похож, но с заменой WebModule на ServiceProcessModule.

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

Надеюсь это поможет. Ник

person Nicholas Blumhardt    schedule 07.12.2010
comment
+1 за модульность. Я использовал Spring.net-Xml-Configuration и имел один файл конфигурации для каждого модуля и один файл конфигурации, который ссылается на файлы конфигурации модуля. Этот подход аналогичен подходу Николаса. - person k3b; 23.12.2010
comment
Как это решить проблему дублирования? Каждый установщик или модуль нужно будет где-то создавать. Если это в клиентском приложении, мне придется повторить это для каждого клиентского приложения. То же самое. Могу ли я определить их на уровне службы приложений? Тогда это противоречит любой конфигурации IOC на уровне службы приложений. - person Jason; 08.02.2011

Я помещаю класс конфигурации в свой проект DDD или DomainModel и вызываю класс конфигурации в пользовательском интерфейсе.

public static class IoCConfigurator()
{
    public static void Initialize()
    {
        // your code here
    }
}

В вашем пользовательском интерфейсе вы должны вызвать только метод Initialize () и все. Вы можете использовать его в своем MVC Global.asax и даже в своем приложении службы Windows. Никакого дублирования кода.

У меня работает очень хорошо.

person Mariusz    schedule 07.12.2010
comment
Как, например, таким способом зарегистрировать веб-типы? Разве IoCConfigurator не нужно знать обо всех возможных средах выполнения и быть привязанными к ним? Если вам нужно зарегистрировать контроллеры MVC в контейнере под веб-хостом, вы, вероятно, также не захотите регистрировать их (или даже развертывать сборку) на хосте процесса службы. - person Nicholas Blumhardt; 08.12.2010
comment
Это зависит от того, какая часть моего проекта в нем задействована. Если мне нужен IoC в моем проекте DomainModel, я создам IoCConfigurator для этих особых зависимостей в этом проекте. Если мне нужен IoC и в моем проекте WebUI MVC, я также создам IoCConfigurator для этого проекта. Я стараюсь, чтобы проект был максимально свободным. Например, когда мне нужна сборка DomainModel в моем проекте WebService, я не буду обрабатывать конфигурацию IoC вручную. Я предполагаю, что в этой сборке есть конфигуратор конкретных зависимостей. - person Mariusz; 08.12.2010