Windsor style convention over configuration in StructureMap
So I was trying to get my BDD project SpecMaker working on Mono only to find out my usual IoC container of choice Castle Windsor does not play nice. StructureMap I’ve heard plays nice in Mono, and I know a bunch of people that use it, so I gave it a whirl.
My original Windsor configuration looked something like this:
var kernel =
new DefaultKernel();
kernel.Register(Component.For
().ImplementedBy(factory)); //load implementation
kernel.Register(
AllTypes.Pick().
FromAssembly(GetType().Assembly).
WithService.FirstInterface(). //regardless of naming first interface is listed as service
Configure(c=>c.LifeStyle.Transient));
</div>
</div>
I changed this to the what I thought was the StructureMap equivalent:
var container =
new Container(registry =>
{ registry.Scan(x =>
{ x.TheCallingAssembly();
x.With
(); //does NOT configure the first service interface
});
});
container.SetDefault(typeof(IReportFactory), new ConfiguredInstance(factory)); //specific implemenation
</div>
</div>
Ok so I ran my code and nearly none of my classes were registered only interfaces and classes that were in a pattern like ISpecFinder/SpecFinder. Looking at SM’s site this is actually expected behavior, and I was not able to find anything that would work the same way as I was used to. I’m not personally a fan of naming interfaces exactly like class names, so after looking around a bit at my options with SM and a brief perusal of Windsor’s source, I used StructureMap’s extensibility to come up with the following:
class FirstInterfaceConvention : TypeRules,ITypeScanner
{ public void Process(Type type, PluginGraph graph)
{ if (!IsConcrete(type))
return;
//only works on concrete types
var firstinterface = type.GetInterfaces().FirstOrDefault();
//grabs first interface
if(firstinterface!=
null)
graph.AddType(firstinterface, type);
//registers type
else { graph.AddType(type);
//adds concrete types with no interfaces
} } } public class IoCConfig { public virtual ISpecRunner InitializeRunner(Type factory)
{ var container =
new Container(x=> x.Scan(
y=>
{ y.TheCallingAssembly();
y.With
();
}
));
container.SetDefault(typeof(IReportFactory), new ConfiguredInstance(factory));
</p>
return container.GetInstance();
}
} </div> </div>
and perfecto! Everything now works as it did before and I was happy that something that wasn’t supported out of the box was so very simple to add myself. Finally, SpecMaker now appears to be working in mono and is nearing a release for me which I will share shortly.