У нас есть ряд компонентов виндзора замка, объявленных в файле конфигурации. Некоторым компонентам, находящимся глубоко внутри, может потребоваться обслуживание других компонентов.Элементы замка располагают заказ
Проблема заключается в том, когда приложение закрывается и контейнер находится в распоряжении. Во время Dispose()/Stop() компонента Startable/Disposable (A), когда он требует услуг другого компонента (B) ComponentNotFoundException, затем поднимается. К этому времени B уже удален из контейнера.
Я заметил, что порядок объявлений компонентов в файле конфигурации приложения важен. И перестановка A и B решает проблему.
Есть ли лучший способ повлиять на порядок расположения компонентов?
Отредактировано: После запроса в комментариях я приведу здесь пример кода, который отбросит ComponentNotFoundException:
class Program
{
static void Main()
{
IoC.Resolve<ICriticalService>().DoStuff();
IoC.Resolve<IEmailService>().SendEmail("Blah");
IoC.Clear();
}
}
internal class CriticalService : ICriticalService, IStartable
{
public void Start()
{}
public void Stop()
{
// Should throw ComponentNotFoundException, as EmailService is already disposed and removed from the container
IoC.Resolve<IEmailService>().SendEmail("Stopping");
}
public void DoStuff()
{}
}
internal class EmailService : IEmailService
{
public void SendEmail(string message)
{
Console.WriteLine(message);
}
public void Dispose()
{
Console.WriteLine("EmailService Disposed.");
GC.SuppressFinalize(this);
}
}
internal interface ICriticalService
{
void DoStuff();
}
internal interface IEmailService : IDisposable
{
void SendEmail(string message);
}
public static class IoC
{
private static readonly IWindsorContainer _container = new WindsorContainer(new XmlInterpreter());
static IoC()
{
_container.AddFacility<StartableFacility>();
// Swapping the following 2 lines resolves the problem
_container.AddComponent<ICriticalService, CriticalService>();
_container.AddComponent<IEmailService, EmailService>();
}
public static void Clear()
{
_container.Dispose();
}
public static T Resolve<T>()
{
return (T)_container[typeof(T)];
}
}
Примечание: см комментарий в коде, как подкачка порядок вставки компонентов в контейнере решает проблему.
Пуск/остановка - две проблемы, обеспечиваемые StartableFacility, и одноразовая - это еще одна проблема, не имеющая принципиального отношения к запуску/остановке. StartableFacility гарантирует, что проблема Stop является первой, которая выполняется при «снятии с эксплуатации» компонента. Если вы говорите, что Dispose() выполняется до Stop(), то это выглядит как ошибка. Можете ли вы показать нам какой-то код, может быть, выставить тестовый файл? –
Спасибо за ваш комментарий. Мне кажется, что когда контейнер размещен, он выполняет итерацию через каждый запускаемый компонент и вызывает каждый Stop(), а затем Dispose() и удаляет его из контейнера. Хотя я ожидаю, что сначала он должен вызвать Stop() для всех запусков, а затем удалить их и удалить из контейнера. –
Да, контейнер выполняет итерацию через каждый запускаемый компонент и вызывает каждый Stop(), а затем Dispose(), это поведение. Можете ли вы разместить тестовый файл, который выдает ComponentNotFoundException? –