Castle.Windsor and lifecycle of objects

In a previous post I discuss about the importance of calling IWindsorContainer.Release() for all object created through Windsor, to avoid memory leak. There is a little correction to do, the container keeps a reference to an object created through Resolve<T> only if that object implements IDisposable. But it is important to really understand the concept of lifecycle of objects in Windsor. Suppose you have an object that implements IDisposable and tells if it was disposed with a simple property called aProperty

public class DisposableTest : ITest {
   
public static Int32 NumOfDispose = 0;
 
   
private byte[] big = new byte[1000000];
 
   #region IDisposable Members
 
   
public Boolean aProperty = false;
 
   
public void Dispose() {
      aProperty = 
true;
      NumOfDispose++;
   }
 
   #endregion
 
   #region ITest Members
 
   
public bool AProperty {
      
get { return aProperty; }
   }
 
   #endregion
}

now configure two component in the config file, one with transient lifecycle and another with singleton lifecycle, this test shows you an important concept

ITest tran, sing;
using (WindsorContainer ioc = new WindsorContainer(new XmlInterpreter(“config1.xml”))) {
   tran = ioc.Resolve<
ITest>(“TransientITest”);
   sing = ioc.Resolve<
ITest>(“SingletonITest”);
}
Assert.IsTrue(tran.AProperty);
Assert.IsTrue(sing.AProperty);

After the container is disposed, it disposes also all transient and singleton objects created with resolve. This is the reason why the container keeps references to transient objects that implement IDisposable. So do not remember to call Resolve for all transient object that are IDisposable if you do not dispose the container itself. Now you can do another test.

using (WindsorContainer ioc = new WindsorContainer(new XmlInterpreter(“config1.xml”))) {
   tran = ioc.Resolve<
ITest>(“TransientITest”);
   sing1 = ioc.Resolve<
ITest>(“SingletonITest”);
   ioc.Release(tran);
   ioc.Release(sing1);
   
Assert.IsTrue(tran.AProperty);
   
Assert.IsFalse(sing1.AProperty);
   sing2 = ioc.Resolve<
ITest>(“SingletonITest”);
   
Assert.AreSame(sing1, sing2);
}

This test shows two distinct things: if you call WindsorContainer.Release only the transient objects gets their Dispose method called, not the singleton one. Moreover, even if you call release on the singleton object, the object gets no removed from the container, if you resolve again, the instance returned is the same as before. So a singleton object lifecycle spans the life of the container, even if the user explicitly calls Release on it. Now to finish this example lets create another class and configure as transient

public class DisposableCon : IDisposable {
 
   
public ITest ITest;
 
   
public DisposableCon(ITest iTest) {
      ITest = iTest;
   }
 
   
public void Dispose() {
 
   }
 }

This class simply declare a Constructor dependency, and implements IDisposable, but in the dispose does not do any stuff. The following test shows you that the container does not keeps a reference nor dispose the inner ITest object.

DisposableCon tran;
using (WindsorContainer ioc = new WindsorContainer(new XmlInterpreter(“config1.xml”))) {
   tran = ioc.Resolve<
DisposableCon>(“TransientDisposableCon”);
}
Assert.IsFalse(tran.ITest.AProperty);

So it is your duty to be sure that the inner objects injected by the container will be disposed correctly.

Alk.

Published by

Ricci Gian Maria

.Net programmer, User group and community enthusiast, programmer - aspiring architect - and guitar player :). Visual Studio ALM MVP

5 thoughts on “Castle.Windsor and lifecycle of objects”

  1. Hi Alk,

    This problem has fascinated me for a while and is one of the reasons that Autofac (http://autofac.org) exists.

    The Autofac approach is a bit different to the way you’d tackle it with MicroKernel – essentially you create a scope for your component resolve operation (usually a request or transaction) and then when that scope is disposed, all of the transient instances created within it will be automatically disposed, too.

    I’m pretty sure this covers the ‘component responsibility’ problem that Hammett is talking about..?

    There is an article on the site but it is pretty brief – check it out and let me know what you think :)

    Nick

  2. Just thought I’d show you how your example test would look:

    // Configure container ‘ioc’ first, then…

    DisposableCon tran;
    using (var context = ioc.CreateInnerContainer()) {
    tran = (DisposableCon)context.Resolve(“TransientDisposableCon”);
    }
    Assert.IsTrue(tran.ITest.AProperty); // Autofac disposes all transient instances

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.