Как поделиться свободной конфигурацией в контейнере Castle Windsor IOC - PullRequest
0 голосов
/ 29 марта 2012

Я пытаюсь создать контейнер IOC в Castle Windsor, конфигурация которого используется для всех сборок.

(Ниже приведен пример того, как это работает в Unity. Я хочу сделать следующее.заставить его работать так же, используя Castle Windsor)

У меня есть следующая конфигурация проекта ...

TestCompany.Services.Host
    (Web project hosting a number of .svc files)
    PrintService.svc
    Web.Config
    Unity.Config

TestCompany.Services.PrintService
     IPrintService.cs
     PrintService.cs

Фактическая реализация моего "PrintService" не реализована внутри моегоServices.Host, но в сборке TestCompany.Services.PrintService.

Как часть моего общего кода проекта (не показан), у меня есть помощник контейнера, который отвечает за загрузку конфигурации Unity ...

public static IUnityContainer GetContainer()
{
    // Checks for existance of container (_container == null) ommitted.
    var section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
    section.Configure(_container, name);
    ...
    ...
}

Этот метод загружает раздел конфигурации Unity из Unity.Config и использует его для настройки контейнера.

Преимущество этого метода заключается в том, что один Unity.Config загружается внутри (я полагаю) AppDomainможет обслуживать несколько сборок.Простой вызов GetContainer () из любой сборки, используемой моим хостом службы, вернет контейнер, заполненный с тем же разрешением типа и т. Д.

Я действительно хочу использовать свободную конфигурацию в Castle Windsor, но я не вижу, как безэтот «общий» файл конфигурации, который можно получить.PrintService и все будущие сервисы должны будут разрешать одни и те же зависимости, и я не хочу повторять мою свободную конфигурацию между этими сервисами.

В идеале мне нужен какой-то контейнер, настроенный в приложении хоста сервиса, который может "«перетекать» во все сборки, которые он использует.

Спасибо.

1 Ответ

0 голосов
/ 02 апреля 2012

Мне кажется, я не понимаю вашего вопроса, но мне кажется, что я понимаю ваш сценарий, и вот как я делаю нечто подобное, если это вообще помогает ...

Моя философия:

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

Итак, давайте рассмотрим пример ...

Прежде всего, давайте просто скажем (для целей моего примера), что IPrintService - это то, что вы хотите зарегистрировать реализацию один раз и использовать во всем приложении, и что у нас есть какой-то другой компонент, который должен быть реализован какой-то внешний модуль из основного приложения. Поэтому мы создаем сборку с именем Common, например, так:

Общее

public interface IPrintService
{
    void Print();
}

public interface IMyService
{
    void DoSomething();
}

Теперь давайте подумаем об основной части приложения (может быть, это приложение ASP .NET, а может и консольное приложение, на самом деле не имеет значения). Здесь мы создаем контейнер и просим его найти все возможные компоненты. Мы можем сделать это так:

Основное применение

// Could be the Global.asax code behind but for simplicity this is 
// just a console application
class Program
{

    private static readonly IWindsorContainer Mycontainer 
        = BootstrapContainer();


    // Allow access to the raw container - this is probably a bad idea but
    // in the rare case that you need it you can get it from here        
    public static IWindsorContainer Container { get { return Mycontainer; } }

    private static IWindsorContainer BootstrapContainer()
    {
        // Here we will just install every IWindsorInstaller found in any
        // assembly in the same folder as the application (so no need for
        // references or anything).
        var c = new WindsorContainer();
        string folder = Path.GetDirectoryName(
            Assembly.GetExecutingAssembly().Location);
        c.Install(FromAssembly.InDirectory(new AssemblyFilter(folder)));
        return c;
    } 
}

// Here is the print service implementation
public class MyPrintService : IPrintService
{
    public void Print()
    {
        // Print!
    }
}

// This is the installer for the main module - here we are saying exactly 
// what is implementing the interface
public class MainApplicationInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, 
                        IConfigurationStore store)
    {
        container
            .Register(Component
                          .For<IPrintService>()
                          .ImplementedBy<MyPrintService>());
    }
}

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

Поэтому остается только использовать эту службу печати и использовать ее. Мы можем сделать это везде, где используется контейнер, поэтому давайте создадим третью сборку, которая ссылается только на * Common (назовем его тестовым модулем.

Тестовый модуль

// This installer installs just the things inside this module since that
// is all it knows about but those things can use things that are 
// registered in the container by anybody.
public class TestModuleInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, 
                        IConfigurationStore store)
    {
        container
            .Register(Component
                          .For<IMyService>()
                          .ImplementedBy<MyServiceThatDoesSomething>());
    }
}

public class MyServiceThatDoesSomething : IMyService
{
    private readonly IPrintService _printService;

    public MyServiceThatDoesSomething(IPrintService printService)
    {
        _printService = printService;
    }

    public void DoSomething()
    {
        // Use the print service!
        _printService.Print();
    }
}

Наконец скомпилируйте все и скопируйте тестовый модуль в ту же папку, что и основное приложение, а затем из основного вы можете сделать это:

Container.Resolve<IMyService>().DoSomething();

И тогда происходит волшебство! Ну, какой-то код выполняется, и вы обнаруживаете, что служба печати вызывается классом из модуля, хотя он ничего не знает об этом.

В любом случае, может быть, это немного помогает, а может и нет, удачи!

...