城堡组件处置订单

时间:2010-02-01 23:15:28

标签: c# .net castle-windsor

我们在配置文件中声明了许多城堡windsor组件。 内部某些组件可能需要其他组件的服务。

问题在于关闭应用程序并处理Container时。在Startable / Disposable组件(A)的Dispose()/ Stop()期间,当它需要某些其他组件的服务时(B)然后引发ComponentNotFoundException。到那时B已经从容器中移除了。

我注意到app app文件中组件声明的顺序很重要。并且重新安排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)];
    }
}

注意:请参阅代码中的注释,了解如何交换容器中插入组件的顺序可以解决问题。

2 个答案:

答案 0 :(得分:5)

通过使用静态IoC类,您实际上将容器用作服务定位器,从而失去了依赖注入的大部分好处。

问题是如果没有正确的注入,Windsor不知道CriticalService - IEmailService依赖关系,因此无法确保正确的处理顺序。

如果重构使此依赖项显式化,Windsor将按正确的顺序处理组件:

internal class CriticalService : ICriticalService, IStartable
{
    private readonly IEmailService email;

    public CriticalService(IEmailService email) {
        this.email = email;
    }
 ...
}

Here's how it would look就像重构一样。

答案 1 :(得分:2)

我个人认为,任何需要按特定顺序调用Dispose()的系统都有设计缺陷。

Dispose() 始终可以安全地致电。只有在处理后使用组件时才会出现错误,然后ObjectDisposedException最有意义。在这种情况下,我会重新组织你的组件,以便他们在Dispose()方法中不使用其他组件(它应该是关于清理每个组件自己的私有资源)。这将完全消除这个问题。