This is the first in a series of posts illustrating custom Windsor registration that I outlined previously on this blog.
The first thing I want to do is revise my Windsor registration code and to pull the registration of the MVC controllers out into a static class and I begin by writing the following specification:
namespace Apollo.Infrastructure.Windsor { [Observations] public class when_registering_mvc_controllers : observations_for_a_static_sut { private static Assembly assembly; private static IWindsorContainer container; private static IController resolvedController; private context c = () => { assembly = Assembly.GetAssembly(typeof(FakeController)); container = new WindsorContainer(); }; private because b = () => { WindsorControllerRegistration.RegisterControllersFrom(assembly, container); resolvedController = container.Resolve<IController>(typeof(FakeController) .FullName.ToLower()); }; [Observation] public void should_be_able_to_resolve_a_known_controller_from_the_container() { resolvedController.should_not_be_null(); } } public class FakeController : IController { public void Execute(RequestContext requestContext) { // do nothing } } }
In the context I am creating a new Windsor container and retrieving the assembly of a known type I want to resolve.
I then perform the action I am testing (in the because method) by registering the controllers and then resolving the controller. Finally I assert that the controller should not be null.
My first implementation of this is:
using System.Reflection; using System.Web.Mvc; using Castle.MicroKernel.Registration; using Castle.Windsor; namespace Apollo.Infrastructure.Windsor { public static class WindsorControllerRegistration { public static void RegisterControllersFrom(Assembly assembly,IWindsorContainer container) { container.Register(Component.For<IController>() .ImplementedBy<FakeController>() .LifeStyle.Transient .Named(typeof(FakeController).FullName.ToLower())); } } }
And I now add a second observation to drive registering all controllers from an assembly:
namespace Apollo.Infrastructure.Windsor { [Observations] public class when_registering_mvc_controllers : observations_for_a_static_sut { private static Assembly assembly; private static IWindsorContainer container; private static IController resolvedController; private static IController resolvedController2; private context c = () => { assembly = Assembly.GetAssembly(typeof(FakeController)); container = new WindsorContainer(); }; private because b = () => { WindsorControllerRegistration.RegisterControllersFrom(assembly, container); resolvedController = container.Resolve<IController>(typeof(FakeController) .FullName.ToLower()); resolvedController2 = container.Resolve<IController>(typeof(FakeController2) .FullName.ToLower()); }; [Observation] public void should_be_able_to_resolve_a_known_controller_from_the_container() { resolvedController.should_not_be_null(); } [Observation] public void should_be_able_to_resolve_a_second_known_controller_from_the_container() { resolvedController2.should_not_be_null(); } } public class FakeController : IController { public void Execute(RequestContext requestContext) { // do nothing } } public class FakeController2 : IController { public void Execute(RequestContext requestContext) { //do nothing } } }
This drives the final implementation as follows:
using System.Reflection; using System.Web.Mvc; using Castle.MicroKernel.Registration; using Castle.Windsor; namespace Apollo.Infrastructure.Windsor { public static class WindsorControllerRegistration { public static void RegisterControllersFrom(Assembly assembly,IWindsorContainer container) { container.Register(AllTypes.FromAssembly(assembly) .BasedOn<IController>() .Configure(c => c.LifeStyle.Transient) .Configure(c => c.Named(c.Implementation.FullName.ToLower()))); } } }
I have now separated my controller registration into its own static class making the way for this to become part of an extensible registration framework in the future.