How I Use Inversion of Control Containers
Some time ago, Krzysztof wrote how he uses IoC containers and asked how other use it. This post is the answer to how I use Castle Windsor container on the applications I develop. With the Castle Windsor 2.5 nearly out, I have created a sample application to show best practices of using an IoC containers. The thing is almost all the resources talk about IoC container usage in web applications so hopefully this post will help you on best practices of using IoC in a rich client applications.
At first to no surprise, you need to initialize the container. This usually is done only once at application startup. With IWindsorInstaller interface this is just a breaze and in fact good practice. I use a GuyWire to initialize the container and register run the installers.
What’s a GuyWire you might ask? According to Wikipedia a guy-wire is a tensioned cable with one end attached to the structure and the other attached to the ground. This term was first used by Fabio to show how to wire the IoC container to the rest of your application, so you get the picture.
public class GuyWire
Fabio’s implementation differs a little bit where your startup application does not need to know about the IoC container at all. You can see how different it is from here. This is only supposed to bootstratp the container.
What does this code do? It tells the Windosr to search the assembly and find all instances of IWindsorInstaller interfaces and call their Install method. This gives us a chance to register various parts of our applications.
This is a neat feature of Castle Windsor where you can create instances of your types without coupling to the container itself. Let’s say you want to create instances of Command object from a factory. All you need to do is to create a factory interface and no implementation is needed! All the hard work is done for you by the container.
public class SaveCommand : Command
and you just need to register the ICommandFactory as a Factory in your, say, CommandInstaller:
public class CommandInstaller : IWindsorInstaller
How does it work? It works based on a few conventions (but you can change them if you need to). Basically in your factory interface, non-void methods will create components and void methods will release them, so in our case CreateCommand will create instances of TCommand and Dispose method will release them from the container.
Most of the people using containers don’t know that they are responsible to cleanup after themselves. Maybe it is a naming problem that makes people think that as far as the components are register as Transient, they are garbage collected after they’ve gone out of scope, but this is not the case. Both Singleton AND Transient component instances are still referenced by the container and you need to make the container release them when you’re done with them.
Not releasing instances of components resolved from the container will result memory leaks. This applies to both Transient and Singleton components.
So how do you go about cleaning up? You can create explicit calls to Container.Release method but this is something you should avoid:
public SaveCommand : Command
Some people will chose not to track components at all! This is done by specifying NoTrackingReleasePolicy when creating the container.
public GuyWire() : this(CreateContainer())
This way the container will no longer keep track of your components, but supposing you want to properly dispose your components, no cleaning up will occur at all!
Proper way of cleaning up, as mentioned above, is to use a factory with a release method. Once you call the release method, container will properly dispose the object and will no longer track it so it will be garbage collected. If your factory interface happens to derive from IDisposable, the call to dispose on the factory level will dispose all components created by that factory.
You can get the source of the sample application which is created using Silverlight 4.0 and Windsor 2.5 from here. There are a few more topics converted in the sample application that I didn’t bring up here so make sure you check out the source code and by all means enlighten me if you have any comments and thoughts on the subject.