Windsor custom lifestyles

Windsor provides you with a pretty limited array of options when it comes to lifestyles:

  • Singleton: each time you resolve, you get the same instance. This is, for some reason, the default lifestyle
  • Transient: each time you resolve, you get a new instance. This is what I would have wanted as default 🙂
  • PerThread: it pools a singleton for each thread, so you’ll always get the same instance if you call resolve from the same thread.
  • Pooled: the documentation is not very clear about this but from the source code it seems that a pool with a given capacity is created and on each resolve one of the objects from the pool is returned. I didn’t check how which object to return is determined.
  • there’s also an undocumented PerWebRequest lifestyle and I assume it does just what it says on the tin.

Let’s say that, as it was in my case, you need a container behavior a little different than one of these: you want the container to return a different instance based on a parameter used during the type’s activation. Example:

 
IDictionary argumentsOne = new Hashtable();
argumentsOne.Add("entity", apple);
_container.Resolve<IViewModel>(argumentsOne); // a new instance 
IDictionary argumentsTwo = new Hashtable();
argumentsTwo.Add("entity", pear);
_container.Resolve<IViewModel>(argumentsTwo); // another new instance
IDictionary argumentsThree = new Hashtable();
argumentsThree.Add("entity", apple);
_container.Resolve<IViewModel>(argumentsThree); // the same instance as when called with argumentsOne

So, to get this kind of behavior from your container you need to implement your own CustomLifestyle. The easy way to do it is to subclass AbstractLifestyleManager, which provides you with some methods you can override. The interesting ones are:

  • Resolve which gets called when you try to resolve the type
  • Release which gets called when you try to release the type
  • Dispose which works as usual
  • Init, a callback invoked when your CustomLifestyle gets constructed

Obviously, Resolve should return the instance of the type, be it from your cache or from calling base.Resolve, which should get you a new one. Release should delete the right element from the cache so the next time Resolve is called a fresh instance is returned.

Here follows a sample implementation for the above scenario.

 
public class PerEntityLifestyleManager : AbstractLifestyleManager
    {
    private IDictionary<object, object> _instances = new Dictionary<object, object>();
        
    public override object Resolve(Castle.MicroKernel.CreationContext context)
    {           
        object param = context.AdditionalParameters["entity"];
        if (!_instances.Keys.Contains(param))
        {
            _instances.Add(param, base.Resolve(context));
        }
        return _instances[param];
    }

    public override bool Release(object instance)
    {
        if (_instances.Keys.Contains(instance))
        {
            _instances.Remove(instance);
            return true;
        }
        return false;
    }
}

You should then apply your lifestyle to the types you want to be resolved with it as an attribute, like this:

 
[CustomLifestyle(typeof(PerEntityLifestyleManager))]
public class MyClass : IMyInterface
{
   
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s