This last week, I was refactoring an older code base with a co-worker that had no tests. As we started looking at the code, I realized that it was untestable as it sat. It seemed like there was a ‘New’ every 100 lines. We moved all the dependencies up using a bit of constructor injection.
As we got things into a testable state, I found we had a stack of ‘news’ at the top of the service, maybe 15 news all in a pile. This made our NUnit test setup harsh, and it was still hard to move classes and methods around. I looked to StructureMap for some relief.
StructureMap is an open source ‘Inversion of Control Container’. It news up your objects as you need them. This will make your code more testable and happy. Goodness knows, we like happy code…
Generally, to use StructureMap, you put interfaces in your constructor parameters instead of primitive types or concrete objects. StructureMap will look for the greediest constructor of each class and try to use that one. It will new up a concrete instantiation of each interface listed in the constructor as it is needed.
To Get Started:
You will have to ‘bootstrap’ the structuremap engine. Below is a sample class that does just that:
public class IocContainerBootstrapper : Registry
{
private static bool _hasStarted;
public static void Bootstrap()
{
new IocContainerBootstrapper().BootstrapStructureMap();
}
public void BootstrapStructureMap() //Initializes the structuremap container
{
ObjectFactory.Initialize(x => x.Scan(scanner =>
{
scanner.TheCallingAssembly();
scanner.WithDefaultConventions();
}
));
}
public static void Restart()
{
if (_hasStarted)
{
ObjectFactory.ResetDefaults();
}
else
{
Bootstrap();
_hasStarted = true;
}
}
}
Once you have this class in place and a reference to StructureMap in your project, call the Bootstrap method from your ‘Main()’ method in a windows service or the global.asax for the web. The bootstrapper example above will look in to the calling assembly. ‘WithDefaultConventions’ will assume that for each interface ‘IThingy’, there will be a concrete class called ‘Thingy’. You can explicitly name which concrete you require if that convention does not work for your situation.
Once you have called the bootstrapper like this:
private static IocContainerBootstrapper _bootStrapper; …
private static void Main(string[] args)
{
_bootStrapper = new IocContainerBootstrapper();
_bootStrapper.BootstrapStructureMap();
You can immediately log out everything StructureMap found to instantiate with something like this log4net call:
Log.DebugFormat(“We bootstrapped ‘{0}’:”, ObjectFactory.WhatDoIHave());
Once you have StructureMap running, you can tell it to spin up an instance of your upper level class like this:
_myThingySettings = ObjectFactory.GetInstance<IMyThingySettings>();
This call will spin up a concrete MyThingySettings and a concrete instance of every interface listed in its constructor. It will also spin up concretes as needed for any of those concretes, all the way down the dependency chain with this one call. You want to do this as high in your call stack as possible. There is a good article to read about this called The Three Calls Pattern in the Castle Project.
Now you have your objects and you can get to work!
Enjoy,
-Jim
Related Links:
http://martinfowler.com/articles/injection.html
http://docs.castleproject.org/Windsor.Three-Calls-Pattern.ashx
http://structuremap.net/structuremap/