I am in the middle of moving over a large body of code to Castle Trunk which includes the new fluent interface for configuring the container. Since the project has a huge windsorConfig xml file that is beyond maintainable, I thought I would start to take advantage of this new feature. I know other containers (e.g. StructureMap 2.0) also contain fluent interfaces for container configuration, so this question isn't based around Windsor.
My question is what conventions/idioms/patterns are you using for container configuration using the new fluent style interfaces?
My first thought was to create a static method somewhere (e.g. ContainerConfig.Config) that would load all the relevant types that the app uses into the container. My worry is eventually this monolithic function would end up being almost as unmaintainable as the xml config file (less the angle bracket tax).
My second thought was to break it down so each dependent assembly, by convention exports its default configuration. I can see this been useful for hierarchies used internally by the assembly. But for types used externally should there configuration even be defined internally?
The more I thought about it the more questions I seemed to raise. What are your thoughts on it?
Take a deeper look at StructureMap 2.5. It offers several features to dramatically reduce the work to bootstrap the IOC container. It offers a convention over configuration technique (see the blog entries below)
See the following recent blog posts from Jeremy Miller (author of StructureMap)
Create your own Auto Registration Convention with StructureMap
// Example from the blog post above
var container = new Container(registry =>
{
registry.Scan(x =>
{
x.TheCallingAssembly();
x.With<DefaultConventionScanner>();
});
});
StructureMap 2.5.2 is Released
I had a project where we were using Unity, and I watched a video about StructureMap and I liked the registration idea from the start.
So I created the following interface:
/// <summary>
/// An interface which must be implemented to create a configurator class for the UnityContainer.
/// </summary>
public interface IUnityContainerConfigurator
{
/// <summary>
/// This method will be called to actually configure the container.
/// </summary>
/// <param name="destination">The container to configure.</param>
void Configure(IUnityContainer destination);
}
And have assemblies offer a default Configurator class. We've also wrapped our Unity IoC using a static class so that we can call IoC.Resolve<T>
, and I just added the following functions to that wrapper:
/// <summary>
/// Configure the IoC
/// </summary>
public static class Configure
{
/// <summary>
/// Configure the IoC using by calling the supplied configurator.
/// </summary>
/// <typeparam name="TConfigurator">The configurator to use</typeparam>
public static void From<TConfigurator>() where TConfigurator : IUnityContainerConfigurator, new()
{
From(new TConfigurator());
}
/// <summary>
/// Configure the IoC using by calling the supplied configurator.
/// </summary>
/// <param name="configurationInterface">The configurator instance to use</param>
public static void From(IUnityContainerConfigurator configurationInterface)
{
configurationInterface.Configure(instance);
}
// other configuration.
}
So in the initialization form either the program or the website I'd just call:
IoC.Configure.From<BLL.DefaultMapping>();
In the BLL there is a class like this:
public class DefaultMapping:IUnityContainerConfigurator
{
public void Configure(IUnityContainer destination)
{
destionation.RegisterType<IRepository, SQLRepository>();
// and more..
}
}
The only downside is that all you're layers are coupled to the chosen IoC container.
Update: Since this answer I have posted an article on my blog containing the Unity wrapper.
Tricky questions [and I'm no IoC expert] but keep in mind that any "monolithic static function" should not be nearly as scary as the config file. You can define your own conventions for things, and try to abstract things down. I use Ninject, but for Windsor, I'd imagine it would involve making short little functions using things like Register with the AllTypesOf strategy:
kernel.Register(AllTypesOf<ISomethingProvider>.
FromAssembly(Assembly.Load("SomeAssembly")));
Don't know about the internal hierarchies exporting their own default configuration. That seems a little scary and inverted.
You could try examining the Ninject framework. Very simple, fluent interface and lightning-fast ;) No XML configuration and the API is quite simple. Highly recommended
Ninject