This page is targeted towards people who already know StructureMap container, and want to get up to speed with Castle Windsor. You will quickly learn about major differences between the two, and how best you can reuse what you already know about StructureMap.
A common technique for using StructureMap is to have a static Bootstrapper
class that initialises the static, ObjectFactory
container, often by adding instances of type Registry
. For example:
public static class Bootstrapper
{
public static void Configure()
{
ObjectFactory.Initialize(x => x.AddRegistry<MyAppRegistry>());
}
}
The entry point to the application will call the Bootstrapper
to initialize the container, and then resolve the type or types needed to start running the application using ObjectFactory.GetInstance<T>()
.
Bootstrapper.Configure();
var shell = ObjectFactory.GetInstance<IApplicationShell>();
shell.Show();
With Windsor the standard approach is to bootstrap a single instance of the container at the entry point of the application and resolve types from that. Windsor's equivalent to a Registry
is an installer -- a class which implements IWindsorInstaller
. The following code will create a new container and install all public IWindsorInstaller
implementations in the current assembly into the container.
public IWindsorContainer BootstrapContainer()
{
return new WindsorContainer()
.Install( FromAssembly.This() );
}
This will be used in the entry point to the application in a similar way to StructureMap. Windsor's equivalent to GetInstance<T>()
is Resolve<T>()
.
var container = BootstrapContainer();
var shell = container.Resolve<IApplicationShell>();
shell.Show();
See Three Calls Pattern for the details and recommendations on how to bootstrap the Windsor container.
For StructureMap type mappings are configured in the constructor of a Registry
sub-class (this example uses the StructureMap 2.6+ syntax).
class MyAppRegistry : Registry
{
public MyAppRegistry()
{
For<IFoo>().Use<Foo>();
For<IBar>().Use<Bar>();
}
}
For Windsor this is done by implementing the Install
method of the IWindsorInstaller
interface.
public class MyAppInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IFoo>().ImplementedBy<Foo>(),
Component.For<IBar>().ImplementedBy<Bar>()
);
}
}
StructureMap has a Scan()
method in the Registry
base class to automatically add type mappings based on various conventions. A common convention is to map implementations to interfaces based on name (e.g. map IFoo
as implemented by Foo
):
public MyAppRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
x.WithDefaultConventions();
});
//No longer required (will be wired up by convention):
//For<IFoo>().Use<Foo>();
//For<IBar>().Use<Bar>();
}
For Windsor we do this by picking types using a specific service.
public class MyAppInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
AllTypes.FromThisAssembly().Pick()
.WithService.DefaultInterfaces()
.Configure(c => c.Lifestyle.Transient);
//No longer required (will be wired up by convention):
//Component.For<IFoo>().ImplementedBy<Foo>(),
//Component.For<IBar>().ImplementedBy<Bar>()
);
}
}
To add a dependency to an auto-wired component, you need to use ConfigureFor
:
container.Register(
AllTypes.FromThisAssembly().Pick()
.WithService.DefaultInterfaces()
.ConfigureFor<ISomething>(c => c.DependsOn(new[] {
Property.ForKey("someKey").Eq("someValue"),
})
);
When multiple implementations of a single interface are registered with StructureMap, then an instance of each implementation will be injected when a collection of that type is requested. For example, if we have these mappings:
For<IFoo>().Use<ThisFoo>();
For<IFoo>().Use<ThatFoo>();
then ObjectFactory.GetInstance<IEnumerable<IFoo>>()
will yield an instance of ThisFoo
and an instance of ThatFoo
.
This behaviour needs to be explicitly configured for Windsor by adding a Resolver
. The following configuration will return an array containing ThisFoo
and ThatFoo
when an array of IFoo
is resolved (container.Resolve<IFoo[]>()
).
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
container.Register(
Component.For<IFoo>().ImplementedBy<ThisFoo>(),
Component.For<IFoo>().ImplementedBy<ThatFoo>()
AllTypes.FromThisAssembly().Pick().WithService.DefaultInterfaces();
);
}
Windsor partitions components into a number of different namespaces. Here is a quick summary of the namespaces used so far.
Behaviour | Required namespaces |
---|---|
Creating a container (new WindsorContainer().Install() ) |
Castle.Windsor |
Basic installer (implementing IWindsorInstaller ) |
Castle.Windsor , Castle.MicroKernel.Registration , Castle.MicroKernel.SubSystems.Configuration |
Resolvers | Castle.MicroKernel.Resolvers and sub-namespaces like SpecializedResolvers which include ArrayResolver |
What's called an instance scope in StructureMap, Windsor calls Lifestyle, as specified in the LifestyleType
enum.
StructureMap | Windsor | Notes |
---|---|---|
Singleton | Singleton | This is the default lifestyle in Windsor |
PerRequest | Transient | Windsor keeps references to transient components! |
ThreadLocal | PerThread | |
HttpContext | PerWebRequest | |
HttpSession | None/Custom | There's no direct equivalent in Windsor for this lifestyle, but implementing one is trivial |
Hybrid | None/Custom | There's no direct equivalent in Windsor for this lifestyle, but implementing one is trivial |
Please note that for PerWebRequest
in Windsor you will need to install the Castle.Facilities.AspNet.SystemWeb
package from NuGet.
StructureMap has ConnectImplementationsToTypesClosing
that can used to register non-generic types with their base generic service. How can I do that with Windsor?
kernel.Register(AllTypes.FromAssembly(Assembly.GetExecutingAssembly())
.BasedOn(typeof(ICommand<>))
.WithService.Base());
You can easily register single component type, to satisfy more than one service in Castle Windsor. For the follwing StructureMap code:
ForRequestedType<IEventStoreUnitOfWork<IDomainEvent>>()
.CacheBy(InstanceScope.Hybrid)
.TheDefault.Is.OfConcreteType<EventStoreUnitOfWork<IDomainEvent>>();
ForRequestedType<IUnitOfWork>()
.TheDefault.Is.ConstructedBy(x => x.GetInstance<IEventStoreUnitOfWork<IDomainEvent>>());
Corresponding Windsor code would be:
container.Register(
Component.For<IUnitOfWork, IEventStoreUnitOfWork<IDomainEvent>>()
.ImplementedBy<EventStoreUnitOfWork<IDomainEvent>>().LifeStyle.PerWebRequest
);
The ability to register component with multiple services is called Type Forwarding, and can be also set from XML configuration.