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.


Posted 01-27-2010 8:57 PM by Krzysztof Koźmic
Filed under:

[Advertisement]

Comments

Michael Sevestre wrote re: Transparently releasing components in Windsor
on 01-27-2010 11:29 PM

I might be missing the point here, but why don't you change the release policy to a NoTrackingReleasePolicy  (default is AllComponentsReleasePolicy I believe) and then take care of the disposing yourself. This could potentially be a problem if you have singleton components that are also disposable,  or if you have components which have already been injected with some  disposable objects. However it seems in that case to be more of a design issue anyway.

In my opinion, disposable objects should almost always be disposed when we are done using them.

Could be sthg like

using(var service =container.Resolve<ISomeService>())

{

// Do stuff here

}

That combine with the NoTrackingReleasePolicy   and you are all set!

Michael

Vish wrote re: Transparently releasing components in Windsor
on 01-28-2010 8:37 AM

Hi,

I was wondering about the realeasing the service instances created by the WCFFacility too. Since I never have to get a reference to the service instance, I can't release it. SO, does the WCFFacility handle releasing the service instances automatically? If so, how?

Thank You,

Vish

Krzysztof Koźmic wrote re: Transparently releasing components in Windsor
on 01-28-2010 9:46 AM

@Vish,

I'm not entirely sure, but WCF runtime manages lifetime of service instances, and I don't think WCF Facility interferes with that.

@Michael,

If you use no tracking release policy, your components will not be tracked by the container, and will not be disposed. Same goes for their dependencies. Also if you had any additional decommission steps, they won't be obviously executed as well.

Aaron Fischer wrote re: Transparently releasing components in Windsor
on 01-28-2010 10:54 AM

Could you use a weak reference in windsor to allow this to be disposed?

Krzysztof Koźmic wrote re: Transparently releasing components in Windsor
on 01-29-2010 3:24 PM

@Aaron Fischer

how?

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)