Custom SimpleInjector Dependency Resolver For Sitecore MVC

UPDATE: 9/17/2015 The code below has been updated in a newer blog post, changes to DI in Sitecore 8.1. After I wrote this post, Steven van Deursen (@dot_NET_Junkie), one of the creators behind SimpleInjector wrote to me to show that there is a better way to do this so that it doesn’t affect upgrades to SimpleInjector for v3, and in the future. Below code will still work, but if you upgrade to v3, you’ll need to change to how it is written in the other post.

 

Dependency Injection – it has been discussed quite a lot in the Sitecore community recently, and as usual, there are many different viewpoints of how it should be implemented. If you are wondering why you should use Dependency Injection in the first place, read:

Once you get through all of that and you are on board, you can start to implement some of this in your Sitecore Implementation.

But – my code works fine…

It probably does – for now. If you went through the above, the key benefit is flexibility. The business sponsor of a Sitecore project is usually the Marketing department of a company, so expect a lot of changes. If the system is built in a way these changes can be implemented without much fuss, you’ll save yourself a lot of headaches, and your marketing department will love you.

DI in the Sitecore Community

This blog post is a little overdue, but I’ve seen in recent times some discussion about how to implement, what IoC container to use, etc. As stated by Anders Laub in his post Simple IoC container using only the Sitecore API, the opinions on this can be religiously charged, almost fanatic. This post presents the case of not adding a third party IoC framework into an already complicated project – instead use the Sitecore API as a framework for your IoC. There are a lot of fans of using the Sitecore API as the IoC – Mike Reynolds has written about it, Leverage the Sitecore Configuration Factory: Inject Dependencies Through Class Constructors and Leverage the Sitecore Configuration Factory: Populate Class Properties with Instances of Types Defined in Configuration.

You can leverage third-party frameworks, as well – Glass Mapper, a popular ORM for Sitecore, comes with Castle Windsor as the IoC; Cris van de Luitgaarden wrote about Using Castle Windsor with Sitecore. There are plenty of third-party frameworks and they vary in implementation methods and speed. Read this for a good comparison.

I am a very big fan of K.I.S.S (keep it simple, stupid) – so my initial instinct is to always implement a solution that I can understand after a few months, or anyone who looks at the code can grasp immediately. There is a very good article (Also by Mark Seemann) about When to Use DI. So, given the problem you are trying to solve, there may not even be a need to introduce DI. But using a good DI framework – whether its poor man’s DI, or the Sitecore Configuration Factory, or a Third-Party Framework, the goal should be easy maintenance and easy growth/expansion. Over the years, I’ve used poor man’s Di many times, but recently started to look into some other frameworks.

Why Simpleinjector?

One of the things I didn’t like about my poor man’s DI implementation is that it mimic’ed the the Service Locater Pattern, and I would need to manually resolve my implementations. The Service Locator pattern also invokes somewhat of a fanatical debate – but what I didn’t like about it was that I would need to have a direct reference to it in the classes in my business layer.

I looked into some of the third party frameworks, and the first one that stuck out in the MVC references was ninject. I tried ninject for a bit, but the performance was really slow. I looked into Castle Windsor, too, but thought it was overkill for what I needed. I’ve heard good things about Autofac, but I’m not too familiar with it. I then looked into Simpleinjector, and it seemed to fit the bill perfectly. It was simple and light, and if needed, I could rip it out of my solution pretty easily and replace it with something else. Moreover, since I can wire up the container at application start, I don’t have to manually find each implementation, which was the key benefit.

Some implementation Issues

The implementation method for Simpleinjector in a MVC project is pretty simple – https://simpleinjector.readthedocs.org/en/latest/quickstart.html.

In an MVC project, you need to initialize your container at application start. The class that Simpleinjector provides for you out of the box looks something like this:


public static class SimpleInjectorInitializer
    {
        
        /// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
        public static void Initialize()
        {
            // Did you know the container can diagnose your configuration? 
            // Go to: https://simpleinjector.org/diagnostics
            var container = new Container();
            
            InitializeContainer(container);

            container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
            
            container.Verify();

            DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
        }
     
        private static void InitializeContainer(Container container)
        {
            InjectorResolver.RegisterImplementations(container);

            // For instance:
            // container.Register<IUserRepository, SqlUserRepository>();
        }
    }

SimpleInjectorDependencyResolver implements IDependencyResolver, which resolves the concrete implementations. Out of the box, this works great. But some browsing around, I started getting errors like this:

15212 23:25:49 ERROR Application error.
Exception: Sitecore.Mvc.Diagnostics.ControllerCreationException
Message: Could not create controller: 'Tests'. 
Source: Sitecore.Mvc
   at Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName)
   at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Nested Exception
Exception: System.InvalidOperationException
Message: An error occurred when trying to create a controller of type 'Sitecore.ContentTesting.Requests.Controllers.Optimization.TestsController'. Make sure that the controller has a parameterless public constructor.
Source: System.Web.Mvc
   at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
   at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName)
   at Sitecore.Apps.TagInjection.DependencyResolver.TagInjectionControllerFactory.CreateController(RequestContext requestContext, String controllerName)
   at Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName)
Nested Exception
Exception: SimpleInjector.ActivationException
Message: No registration for type TestsController could be found and an implicit registration could not be made. For the container to be able to create TestsController, it should contain exactly one public constructor, but it has 2.
Source: SimpleInjector
   at SimpleInjector.Container.ThrowMissingInstanceProducerException(Type serviceType)
   at SimpleInjector.Container.GetInstanceFromProducer(InstanceProducer instanceProducer, Type serviceType)
   at SimpleInjector.Container.GetInstance(Type serviceType)
   at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)

Turns out, once you initialize the application with the SimpleInjectorDependencyResolver container, ALL controllers are being resolved with SimpleInjectorDependencyResolver – even implementations that you never registered in your container, and thus the error.

The Solution

Since SimpleInjectorDependencyResolver isn’t aware of the Sitecore controllers, we have to make our own class that implements IDependencyResolver:

public class CustomDependencyResolver : IDependencyResolver
    {

        public Container Container { get; private set; }

        public CustomDependencyResolver(Container container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            this.Container = container;
        }

        public object GetService(Type serviceType)
        {
            if (serviceType.Assembly.FullName.StartsWith("Sitecore"))
            {
                return Sitecore.Mvc.Helpers.TypeHelper.CreateObject<IController>(serviceType, new object[0]);
            }
            if (!serviceType.IsAbstract && typeof(IController).IsAssignableFrom(serviceType))
            {
                return this.Container.GetInstance(serviceType);
            }
            return ((IServiceProvider)this.Container).GetService(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return this.Container.GetAllInstances(serviceType);
        }

    }

What this is doing is essentially implementing a custom GetService method, which checks to see if the assemblyname begins with Sitecore. If it does, it uses Sitecore MVC helpers to create the instance. If not, then it checks to see if the serviceType being requested is abstract/interface – then it gets the concrete implementation from the SimpleInjector container – the ones that we registered. And lastly, once this class is done, instead of using SimpleInjectorDependencyResolver in the Application Initialize, we use our class CustomDependencyResolver:

Instead of this:

DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));

..do this:

DependencyResolver.SetResolver(new CustomDependencyResolver(container));

All the errors for any other controller instantiation should now go away.

Conclusion

Dependency Injection and the choice of DI frameworks remain a hot topic still. The issue I faced is one argument against using a third party framework, but SimpleInjector is light enough that it doesn’t intrude too much into my application. I’m hoping this can help anybody who uses SimpleInjector. The bottomline is, you really have to take a good look at your application before you make a choice to commit to an IoC framework, because some of the more complicated ones can really be a large commitment, so choose wisely!

Advertisement

2 thoughts on “Custom SimpleInjector Dependency Resolver For Sitecore MVC

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s