Sitecore and Castle Windsor DI

Keeping your Sitecore solutions as simple as possible is generally a good thing. It lessens the risk of bugs or re-work when you have to upgrade to a new version. If you want to use DI, it’s probably a good idea to leverage the OOTB support for DI that comes with Sitecore. Simplicity and elegance are key to having well architected and maintainable Sitecore solutions. Write less code, use more OOTB features, and adhere to the Helix principles Sitecore provides.

If you choose to roll your own DI and want to use Castle Windsor, or a different library, you will run into issues with Sitecore resolving dependencies. There are solutions out there that use a chained dependency resolver, which works great. A possible alternative to try is the chained controller factory.

Chained Controller Factory

The inspiration for this should be credited to this article. How does this apply to Sitecore? First we need to setup our chained controller factory. It’s quite simple. This chained controller factory has a Register method on it. Other controller factories will get registered with the Chained Controller factory and get stored in a list of “factories”.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;

namespace SampleSite.DependencyInjection
{
    public class ChainedControllerFactory : IControllerFactory
    {
        protected List<IControllerFactory> factories = new List<IControllerFactory>();

        private Dictionary<string, IControllerFactory> FactoriesByControllerName;

        public ChainedControllerFactory Register(IControllerFactory factory)
        {
            factories.Add(factory);
            return this;
        }

        public IController CreateController(RequestContext requestContext, string controllerName)
        {
            foreach (var factory in factories)
            {
                IController controller = null;

                try
                {
                    controller = factory.CreateController(requestContext, controllerName);
                }
                catch (Exception ex)
                {
                    controller = null;
                }

                if (controller != null)
                {
                    return controller;
                }
            }

            return null;
        }

        public void ReleaseController(IController controller)
        {
            foreach (var factory in factories)
            {
                factory.ReleaseController(controller);
            }
        }

        public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
        {
            foreach (var factory in factories)
            {
                var s = factory.GetControllerSessionBehavior(requestContext, controllerName);
                if (s != SessionStateBehavior.Default)
                {
                    return s;
                }
            }

            return SessionStateBehavior.Default;
        }
    }
}

During the start of your application you will call a method to “Register” your controller factories. In the “Register” method, we are doing the following:

  • Getting the default controller factory
  • Creating a new SitecoreControllerFactory and setting the inner factory to the default controller factory. The SitecoreControllerFactory will call the inner factory’s CreateController if it can’t create the controller needed.
  • Creating a new WindsorControllerFactory
  • Creating the ChainedControllerFactory. Here, we are registering both the Sitecore controller factory and the Windsor controller factory.
  • Finally, we set the applications controller factory to be the Chained Controller Factory.
using System.Web.Mvc;
using Castle.Windsor;
using Sitecore.Diagnostics;
using Sitecore.Mvc.Controllers;

namespace SampleSite.DependencyInjection
{
    public class WindsorControllerFactoryRegistrar
    {
        public IWindsorContainer Container { get; set; }

        public WindsorControllerFactoryRegistrar(IWindsorContainer container)
        {
            Assert.IsNotNull(container,
                string.Format("Parameter 'container' must not be null in {0}", this.GetType().FullName));
            Container = container;
        }

        public void Regsiter()
        {
            var currentControllerFactory = ControllerBuilder.Current.GetControllerFactory();
            var sitecoreControllerFactory = new SitecoreControllerFactory(currentControllerFactory);
            var windsorControllerFactory = new WindsorControllerFactory(Container.Kernel);

            ChainedControllerFactory chainedControllerFactory = new ChainedControllerFactory();
            chainedControllerFactory
                .Register(sitecoreControllerFactory)
                .Register(windsorControllerFactory);

            ControllerBuilder.Current.SetControllerFactory(chainedControllerFactory);
        }
    }
}

When the “CreateController” method is called on our ChainedControllerFactory, it will loop through all of the registered controller factories, asking them to try to create the controller.

About Phil Paris

Hi, my name is Phil Paris and I’m a Sitecore Architect and general Sitecore enthusiast. I’ve been working with Sitecore since 2013. Through this blog I will be sharing Sitecore insights, tips and tricks, best practices and general knowledge with the hopes to further the community at large. Please feel free to reach out to me at any time!

View all posts by Phil Paris →