Monday, March 9, 2009

Castle: Pick Your Lifestyle

Post 2 in a 101 series on the Castle IOC project called Windsor. See part one for background

Lifestyle Management

Often you will want to control the lifestyle of the object you create, eg a common but over used lifestyle is the singleton. Using an IoC container means you do not have to manage this in your code, which means other dependencies don't have to implicitly know they are dealing with a singleton (or whatever lifestyle is being implemented). This is good and drastically cleans up production code and makes it a lot easier to test.

So lets have a look at a new implementation we have here the MultiGreeter; a concrete implementation (or component) that tells you how often this instance has greeted you.

class MultiWriter : IWriter
{
private int timesGreeted = 0;
public void Write()
{
Console.WriteLine("I have greeted you " + timesGreeted + " time(s) before");
timesGreeted++;
}
}

We change the program class so we register our new component and resolve the service a couple of times to see the output:


using System;
using Castle.Windsor;

namespace CastleIocConsole
{
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.AddComponent<IWriter, MultiWriter>();
var writer1 = container.Resolve<IWriter>();
writer1.Write();
var writer2 = container.Resolve<IWriter>();
writer2.Write();
var writer3 = container.Resolve<IWriter>();
writer3.Write();
Console.ReadKey();
}
}
}

The output is somewhat unexpected for new comers:


I have greeted you 0 time(s) before
I have greeted you 1 time(s) before
I have greeted you 2 time(s) before

Even though we have resolved the service each time to a new variable the count is incrementing. This is because Castle will resolve types as singletons by default. What we can do, if this lifestyle is inappropriate, is specify that we want the type to be of a differing type,transient for example, which would give the same behaviour associated with calling the constructor of the component each time we resolve the service (ie var writer = new MultiWriter()). This requires are slightly different way of registering our components by using the AddComponentWithLifestyle method and use the Castle.Core.LifeStyleType enumeration to select our desired lifestyle.


using System;
using Castle.Windsor;
using Castle.Core;

namespace CastleIocConsole
{
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.AddComponentWithLifestyle<IWriter, MultiWriter>(LifestyleType.Transient);
var writer1 = container.Resolve<IWriter>();
writer1.Write();
var writer2 = container.Resolve<IWriter>();
writer2.Write();
var writer3 = container.Resolve<IWriter>();
writer3.Write();
Console.ReadKey();
}
}
}

The output is now the expected:


I have greeted you 0 time(s) before
I have greeted you 0 time(s) before
I have greeted you 0 time(s) before

This is because each time we resolve a brand new instance is created. The other Lifestyle I like is PerWebRequest (for obvious reasons).


Next we control our dependencies


Back to Post 1

3 comments:

Colin Scott said...

Transient lifecycles in Castle by default cause Castle to hold a reference until you explicitly call Release(). This has the potential to cause some nasty resource leakage. It's particularly problematic when your application architecture makes it difficult or impossible to know when to make the call.

You can change this behaviour. Unfortunately where I've encountered it the change would have to be low level with the potential to break everything in a reasonably large system and hence in not feasible.

This is not to say Castle is bad just that you need to be aware of this behaviour or you can get some very nasty resource leaks. On the plus side you then get to play with memory profiles which can be fun.

Personally I'm using StructureMap a lot these days, primarily due to the auto-registration. I'm reasonably sure you could do such a thing in Castle, I just like the StructureMap syntax.

Unknown said...

YEah release, not the coolest part of castle; To be honest I have never really liked the singleton nature of Castle.. but thats just me. The real reason behind these posts is that I think Castle is a stack that any senior dev (and up) should know well as it really is the default stack in so many OSS applications. From there you can make educated descions to move to a differnt IoC Container, MVC framework, AR approach and AOP approach. No other stack give all of that with a relatively easy to use API. I feel thee way Castle exposes the user to all of the these constructs the most benficial part of it. Hopefully i can show a few more cool thing s with castle that can get people to think about actually using a non M$ framework to help build better applications.
As for auto registraion, yeah its pretty easy to roll in just about any IoC tool, reflection does pay off sometimes. Hammet has a post on that somewhere and the MVC contrib i know uses it.

Colin Scott said...

I agree. Knowing the concepts is the important thing, the actual framework chosen less so. I decided to give StructureMap a go to see how it differs from what else I've used and I quite like it. But I'd not be upset to have Castle or Spring.NET or the like on a project.

The main thing I try to avoid these days is abstracting the DI framework. In a reusable framework where the components may need to work with multiple DI frameworks I can see some utility. In the application proper I generally feel that if you're tied to a particular DI framework so heavily you worry about changing it then you're probably using it wrong. Most code should be unaware of the DI framework (but aware of DI in general).