Inversion of Control (IoC) is quite a big step for some developers, but the benefits once implemented are huge. With the applications performance, maintainability, unit testing and more importantly separation of concerns, just to name a few.
Basic Registration
The starting point for registering anything in the container is the container’s Register method, with has one or more IRegistration objects as parameter. The simplest way to create those objects is using the static Castle.MicroKernel.Registration.Component class. Its For method returns a ComponentRegistration that you can use to further configure the registration.
Isolate your registration code: It is a recommended practice to keep your registration code in a dedicated class(es) implementing IWindsorInstaller.
Install infrastructure components first: Some components may require a facility or other extension to the core container to be registered properly. As such it is recommended that you always register your facilities, custom subsystems, Component model creation contributors etc before you start registering your components.
To register a type in the container
container.Register( Component.For(MyServiceImpl) );
This will register type MyServiceImpl as service MyServiceImpl with default lifestyle (Singleton).
To register a type as non-default service
container.Register( Component.For(IMyService).ImplementedBy(MyServiceImpl));
Note that For
and ImplementedBy
also have non-generic overloads.
// Same result as example above. container.Register(Component.For(typeof(IMyService)) .ImplementedBy(typeof(MyServiceImpl)) );
Services and Components: You can find more information about services and components here.
To register a generic type
Suppose you have a IRepository<TEntity> interface, with NHRepository<TEntity> as the implementation.
You could register a repository for each entity class, but this is not needed.
// Registering a repository for each entity is not needed. container.Register( Component.For<IRepository<Customer>>() .ImplementedBy<NHRepository<Customer>>(), Component.For<IRepository<Order>>() .ImplementedBy<NHRepository<Order>>(), // and so on... );
One IRepository<> (so called open generic type) registration, without specifying the entity, is enough.
// Does not work (compiler won't allow it): container.Register( Component.For<IRepository<>>() .ImplementedBy<NHRepository<>>() );
Doing it like this however is not legal, and the above code would not compile. Instead you have to use typeof()
// Use typeof() and do not specify the entity: container.Register( Component.For(typeof(IRepository<>)) .ImplementedBy(typeof(NHRepository<>)) );
Configuring component’s lifestyle
container.Register( Component.For<IMyService>() .ImplementedBy<MyServiceImpl>() .LifeStyle.Transient );
When the lifestyle is not set explicitly, the default Singleton lifestyle will be used.
Register more components for the same service
You can do this simply by having more registrations for the same service.
container.Register( Component.For<IMyService>().ImplementedBy<MyServiceImpl>(), Component.For<IMyService>().ImplementedBy<OtherServiceImpl>() );
When a component has a dependency on IMyService, it will by default get the IMyService that was registered first (in this case MyServiceImpl).
In Windsor first one wins: In Castle, the default implementation for a service is the first registered implementation.
You can force the later-registered component to become the default instance via the method IsDefault.
container.Register( Component.For<IMyService>().ImplementedBy<MyServiceImpl>(), Component.For<IMyService>().Named("OtherServiceImpl") .ImplementedBy<OtherServiceImpl>().IsDefault() );
In the above example, any component that has a dependency on IMyService, will by default get an instance of OtherServiceImpl, even though it was registered later.
Of course, you can override which implementation is used by a component that needs it. This is done with service overrides.
When you explicitly call container.Resolve<IMyService>() (without specifying the name), the container will also return the first registered component for IMyService (MyServiceImpl in the above example).
Provide unique names for duplicated components: If you want to register the same implementation more than once, be sure to provide different names for the registered components.
Using a delegate as component factory
You can use a delegate as a lightweight factory for a component:
container.Register( Component.For<IMyService>() .UsingFactoryMethod( () => MyLegacyServiceFactory.CreateMyService()) );
UsingFactoryMethod method has two more overloads, which can provide you with access to kernel, and creation context if needed.
Example of UsingFactoryMethod with kernel overload (Converter)
container.Register( Component.For<IMyFactory>().ImplementedBy<MyFactory>(), Component.For<IMyService>() .UsingFactoryMethod(kernel => kernel.Resolve<IMyFactory>().Create()) );
In addition to UsingFactoryMethod method, there’s a UsingFactory method. (without the “method” suffix 🙂 ). It can be regarded as a special version of UsingFactoryMethod method, which resolves an existing factory from the container, and lets you use it to create instance of your service.
container.Register( Component.For<User>().Instance(user), Component.For<AbstractCarProviderFactory>(), Component.For<ICarProvider>() .UsingFactory((AbstractCarProviderFactory f) => f.Create(container.Resolve<User>())) );
Avoid UsingFactory: It is advised to use UsingFactoryMethod, and to avoid UsingFactory when creating your services via factories. UsingFactory will be obsoleted/removed in future releases.
OnCreate
It is sometimes needed to either inspect or modify created instance, before it is used. You can use OnCreate method to do this
container.Register( Component.For<IService>() .ImplementedBy<MyService>() .OnCreate((kernel, instance) => instance.Name += "a") );
The method has two overloads. One that works with a delegate to which an IKernel and newly created instance are passed. Another only takes the newly created instance.
OnCreate works only for components created by the container: This method is not called for components where instance is provided externally (like when using Instance method). It is called only for components created by the container. This also includes components created via certain facilities (Remoting Facility, Factory Support Facility)
A good source of reference is the Castle Windsor documentation, which can be found here:
https://github.com/castleproject/Windsor/tree/master/docs
Here is a sample project with examples and a MVC application showing how it all works