Transparently releasing components in Windsor

Disclaimer:

This post is about the idea, not about the implementation. The implementation is crippled, not thread safe, will work only in few scenarios and only if used properly. Do not copy and blindly use this code.

The problem

One of unique features of Windsor is that it manages the lifecycle of objects it creates for you. What this means (among other things) is that it will dispose all disposable objects it instantiates. However to do this, it has to keep a reference to these components. Also that means that in order to properly release the components you have to get hold of the container and once you’re done using the components – explicitly release them with the container.

It may be not desirable from your perspective to do it like this. Ideally, you’d rather use your component, call Dispose and then have Windsor release the component. This is not quite possible, since there’s no way by which Windsor can be notified that your component was disposed. Or is there?

The idea

Since Dispose is an interface method and Windsor has quite powerful AOP capabilities, we can take advantage of that and intercept the call to Dispose and transparently release our component. Let’s build a disposable component first:

public interface IController : IDisposable

{

    int DoSomething();

 

    bool Disposed { get; set; }

}

 

public class Controller : IController

{

    // notice it's not virtual!

    public void Dispose()

    {

        // some clean up logic here

        Disposed = true;

    }

 

    public int DoSomething()

    {

        return 42;

    }

 

    public bool Disposed

    {

        get; set;

    }

}

One important thing to notice about this code – Dispose is not implemented virtually. This will make our sample simpler since we won’t have to deal with recursion.

Then we set up the stage:

[TestFixture]

public class TransparentReleasingTest

{

    private WindsorContainer container;

 

    [SetUp]

    public void SetUp()

    {

        container = new WindsorContainer();

        container.Register(Component.For<ReleaseComponentInterceptor>());

        container.Register(Component.For<IController>().ImplementedBy<Controller>()

                               .LifeStyle.Transient

                               .Interceptors<ReleaseComponentInterceptor>());

    }

 

    [TearDown]

    public void CleanUp()

    {

        container.Dispose();

    }

}

We’ll discuss the ReleaseComponentInterceptor, which is the gist of this post, in a minute. Let’s first create a test:

[Test]

public void Dispose_releases_component()

{

    IController item;

    using (var controller = container.Resolve<IController>())

    {

        item = controller;

        controller.DoSomething();

 

        Assert.IsTrue(container.Kernel.ReleasePolicy.HasTrack(controller));

        Assert.IsFalse(controller.Disposed);

    }

 

    Assert.IsFalse(container.Kernel.ReleasePolicy.HasTrack(item));

    Assert.IsTrue(item.Disposed);

}

Notice that in order for the interceptor to intercept the call to Dispose we need to cast component to IDisposable before calling the method (‘using’ will do that for us). Notice important aspect of this test – it is completely container agnostic. It does not need any kind of explicit nor indirect reference to the container to work and to release the component properly. Let’s now see what happens behind the scenes.

Interceptor

The hero of the day, is the following interceptor:

[Transient]

public class ReleaseComponentInterceptor : IInterceptor

{

    private static readonly MethodInfo dispose = typeof(IDisposable).GetMethods().Single();

    private readonly IKernel kernel;

 

    public ReleaseComponentInterceptor(IKernel kernel)

    {

        this.kernel = kernel;

    }

 

    public void Intercept(IInvocation invocation)

    {

        if (invocation.Method == dispose)

        {

            kernel.ReleaseComponent(invocation.Proxy);

        }

        else

        {

            invocation.Proceed();

        }

    }

}

Most of the time it just sits there and does nothing. However if it detects a call to Dispose, it releases the component from the container, which will in turn invoke the Dispose again (this time on the class, not interface, and since the interface is implemented non-virtually that second call won’t be intercepted), perform all other decommission job for the component as well as all its dependencies and it will release it, so that it can be garbage collected afterwards.

This is just another useful trick, worth knowing if you want to keep your design container agnostic while still reaping full benefits it provides.

Comments

John Simons says:

Krzysztof, wouldn’t you still want to call the Dispose implementation of the Controller?
So the Intercept method should be:
public void Intercept(IInvocation invocation)
{
invocation.Proceed();

if (invocation.Method == dispose)
{
kernel.ReleaseComponent(invocation.Proxy);
}
}

John,

Not really. When I ReleaseComponent, the container will call Dispose.