Using Castle Windsor with Sitecore MVC for Dependency Injection

The preview release of Sitecore 6.6 comes with first class support for ASP.NET MVC. If you want to get serious about MVC programming the first thing you’re going to want to do is to add support for your favourite dependency injection container. In this post I will show you how to add support for Castle Windsor.

First you need to create a new controller factory for ASP.NET MVC that can resolve controller types via Castle Windsor.

using System;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web;
using Castle.MicroKernel;

public class WindsorControllerFactory : DefaultControllerFactory
{
   private readonly IWindsorContainer _container;

   public WindsorControllerFactory(IWindsorContainer container)
   {
      _container = container;
   }

   public override void ReleaseController(IController controller)
   {
      _container.Release(controller);
   }

   protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
   {
      if (controllerType == null)
      {
         throw new HttpException(404,
            String.Format("The controller for path '{0}' could not be found.",
               requestContext.HttpContext.Request.Path));
      }

      return (IController)_container.Resolve(controllerType);
   }
}

If this was standard ASP.NET MVC, you could configure this controller in the Global.asax and be done with it. However, that won’t work with Sitecore MVC as it overrides the controller in the loader pipeline processor, so you will need to override the relevant pipeline processor.

Here’s the code that adds the Castle Windsor controller factory to the Sitecore loader pipeline:

using System;
using System.Linq;
using System.Web.Mvc;
using Castle.Windsor;
using Castle.MicroKernel.Registration;
using Castle.Windsor.Installer;
using ScapiPipelineArgs = global::Sitecore.Pipelines.PipelineArgs;
using ScapiSitecoreControllerFactory = global::Sitecore.Mvc.Controllers.SitecoreControllerFactory;

public class InitializeWindsorControllerFactory
{
   public virtual void Process(ScapiPipelineArgs args)
   {
      SetupControllerFactory(args);
   }

   protected virtual void SetupControllerFactory(ScapiPipelineArgs args)
   {
      IWindsorContainer container = new WindsorContainer();

      container.Install(FromAssembly.This());

      container.Register(Classes.FromThisAssembly().BasedOn<IController>().LifestylePerWebRequest());

      IControllerFactory controllerFactory = new WindsorControllerFactory(container);

      ScapiSitecoreControllerFactory scapiSitecoreControllerFactory = new
      ScapiSitecoreControllerFactory(controllerFactory);

      ControllerBuilder.Current.SetControllerFactory(scapiSitecoreControllerFactory);
   }
}

Now all you have to do is update the configuration Sitecore.Mvc.config (or apply a patch file).

Delete this line:

<processor type="Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc"/>

Replace with this line:

<processor type="[namespace].InitializeWindsorControllerFactory, [assembly]"/>

Note that you’ll have to replace [namespace] and [assembly] with the namespace of your InitializeWindsorControllerFactory and the name of the assembly it’s compiled in.

Now you should be able to use Castle Windsor with Sitecore MVC. All that's left is for you to add your own registrations to the container.