My favorite hook in the ASP.NET MVC framework is the controller factory. I like it so much because it serves as a very simple entry point to the application, thus providing the perfect place to insert an IoC container. My container of choice is Castle Windsor – not because I have tried any other container – I really can’t say that I have – but because I just happened to be introduced by a colleague to Windsor, and I have yet to experience anything it can’t do for me!
An ASP.NET MVC controller factory is an implementation of the IControllerFactory interface – a simple interface with two methods: one that provides an IController given a string and some more stuff, and one that allows the controller to clean up any resources it might have allocated. The interface looks like this:
1 2 3 4 5 |
public interface IControllerFactory { IController CreateController(RequestContext requestContext, string controllerName); void ReleaseController(IController controller); } |
As you can see, it provides a means to return a controller, given all sorts of information about the current request and what could be resolved as the controllerName from the request URL.
ASP.NET MVC accesses the controller factory via the ControllerBuilder class – so if we want to provide our own controller factory, we must install the factory before any requests get served. An obvious place to do this, is the Application_Start method inside the global.asax.cs file. This way our controller factory will be installed every time the web application starts up.
The controller factory can be set in two ways: 1) By providing the type of the factory, and 2) By providing an instance of the factory. Then it’s up to you if you want to let ASP. NET MVC instantiate the factory. I usually do it like this:
1 2 3 4 5 6 |
public void Application_Start() { RegisterRoutes(RouteTable.Routes); ControllerBuilder.SetControllerFactory(typeof(MyControllerFactory)); } |
– and let ASP.NET MVC instantiate and store a singleton instance of my factory.
My controller factory implementation looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class MyControllerFactory : IControllerFactory { IWindsorContainer container = CreateWindsorContainer(); public IController CreateController(RequestContext requestContext, string controllerName) { return container.Resolve<IController>(controllerName.ToLowerInvariant()); } public void ReleaseController(IController controller) { container.Release(controller); } static IWindsorContainer CreateWindsorContainer() { return new WindsorContainer("windsor.config"); } } |
Very simple. It takes the string, that was resolved as the controller name – e.g. “home”, “hOme”, “HOME” or whatever – and converts it to lower case, and then it uses that to look up a controller in my container. This means that all my controllers are registered in the container, and they will have all their dependencies automatically resolved when the container creates each instance.
A controller registration might look like this:
1 2 3 4 5 6 7 8 |
<castle> <components> <component id="home" type="WebSite.Controllers.HomeController, WebSite" /> <!-- more registrations here... --> </components> </castle> |
Simple – yet incredibly effective!