Чтобы использовать один и тот же контейнер Castle во всем приложении, создайте статический класс, например:
public static class CastleContainer {
private static IWindsorContainer container;
public static IWindsorContainer Instance {
get {
if (container == null) {
container = new WindsorContainer();
}
return container;
}
// exposing a setter alleviates some common component testing problems
set { container = value; }
}
// shortcut to make your life easier :)
public static T Resolve<T>() {
return Instance.Resolve<T>();
}
public static void Dispose() {
if (container != null)
container.Dispose();
container = null;
}
}
Затем зарегистрируйте / установите все свои компоненты методом Main()
. Вы также можете подключиться к событию завершения работы приложения, чтобы вызвать Dispose()
(хотя это не критично).
Касл фактически использует приложение Windows Forms в своем кратком руководстве .
Edit:
Шаблон, который я показал выше, является вариантом сервисного локатора, который некоторые люди называют анти-паттерном. У него плохая репутация, потому что, помимо прочего, он освещает вашу базу кода ссылками на Виндзор. В идеале вам нужно всего лишь один вызов container.Resolve<...>()
, чтобы создать корневую форму. Все остальные сервисы и формы внедряются через конструкторы.
Реально вам, вероятно, понадобится еще несколько вызовов Resolve, особенно если вы не хотите загружать каждый угол приложения при запуске. В мире Интернета лучшая практика - передать контейнер веб-инфраструктуре. В мире Windows Forms вам нужно реализовать свой собственный локатор служб, как описано выше. (Да, передача контейнера в каркас ASP.NET MVC по-прежнему является шаблоном поиска служб).
Я отредактировал приведенный выше пример кода так, что статический контейнер можно вводить; никакие ресурсы не связаны в статическом контексте. Если вы в конечном итоге создадите свой собственный локатор служб, вы также можете создать такую утилиту для тестирования, чтобы упростить тестирование.
public static class TestUtilities
{
public static IContainer CreateContainer(Action<IContainer> extraConfig = null)
{
var container = new WindsorContainer();
// 1. Setup common mocks to override prod configuration
// 2. Setup specific mocks, when provided
if (extraConfig != null)
extraConfig(container);
// 3. Configure container with production installers
CastleContainer.Instance = container;
return container;
}
}
Это делает ярлык для создания нового контейнера, который очень похож на рабочую версию, но с некоторыми службами, замененными на макеты. Некоторые примеры тестов могут выглядеть так:
[Test]
public void SubComponentWorksGreat()
{
using (var container = TestUtilities.CreateContainer())
{
var subComponent = container.Resolve<SubComponent>();
// test it...
}
}
[Test]
public void SubComponentWorksGreatWithMocks()
{
var repoMock = new Mock<IRepository>();
using (var container = TestUtilities.CreateContainer(c =>
c.Register(Component.For<IRepository>().Instance(repoMock.Object))))
{
var subComponent = container.Resolve<SubComponent>();
// test it with all IRepository instances mocked...
}
}
Последнее замечание. Создание полного контейнера для каждого теста может стоить дорого. Другим вариантом является создание полного контейнера, но только с использованием вложенных контейнеров для реальных испытаний.