Recently we decided to integrate Autofac in our Sitecore MVC Solution. After a bit of research I found some pretty nice and useful articles on the topic of using Dependency Injection with Sitecore MVC, but there wasn’t anything focused on Autofac, so I decided to put a blog post around it. The approach is based on a blog article about Ninject, by Mark Cassidy Thomas Stern – Sitecore MVC new Ninject Controller Factory and the Sitecore Mvc Contrib amazing sample implementation by Kevin Obee.
So to build our Autofac Injection we basically need 4 things:
- An Autofac Container Factory, which is going to build the Autofac Container
- An Autofac Controller Factory, which is going to replace the Sitecore Controller Factory
- Replacement Pipeline that is going to initialize the Autofac Container and replace the default Sitecore controller Factory with the custom Autofac Controller Factory
- Configuring the pipeline to replace the default Sitecore Pipeline.
Building an Autofac Container Factory
The first step is to create an Autofac Container Factory. It needs to build the container, register the controllers in our scope and to leave us a place to register all other Modules,Types, etc. we need to register. For ease of use I am also going to use the Autofac MVC 5 Integration Package which provides a method called RegisterControllers which is going to be used in the Controller Registration. The sample code can be found bellow:
using System; using Autofac; using Autofac.Integration.Mvc; namespace AutofacDependancyResolver.DependancyResolution.AutoFac.Factory { public class AutofacContainerFactory { public IContainer Create() { var builder = new ContainerBuilder(); // Register All Controllers In The Current Scope builder.RegisterControllers(AppDomain.CurrentDomain.GetAssemblies()).InstancePerRequest(); // Register Modules builder.RegisterModule<ServicesModule>(); // Register Additional Things // ... // Build The Container and return it as a result return builder.Build(); } } }
So what the code actually does is creating a new ContainerBuilder which is used to build the Container, registers all controllers in the current domain (only controllers), registration of a custom module (not required) and returns the built container as a result. And that is it – simple as that 🙂
Building an Autofac Controller Factory
In order to build a custom Controller Factory, the class needs to implement from the DefaultControllerFactory. It comes with 2 Important Methods that must be overridden:
- GetControllerInstance – which is going to resolve the controller out of our IoC Container
- ReleaseController – which is irrelevant for Autofac Managed Application, as the release is done by the IoC container.
using System; using System.Web; using System.Web.Mvc; using System.Web.Routing; using Autofac; namespace AutofacDependancyResolver.DependancyResolution.AutoFac.Factory { public class AutofacControllerFactory : DefaultControllerFactory { private readonly IContainer _container; public AutofacControllerFactory(IContainer container) { if (container == null) { throw new ArgumentNullException(nameof(container)); } _container = container; } protected override IController GetControllerInstance(RequestContext context, Type controllerType) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (controllerType == null) { throw new HttpException(404, string.Format("No Controller Type Found For Path {0}", context.HttpContext.Request.Path)); } object controller; if (_container.TryResolve(controllerType, out controller)) { return (IController) controller; } throw new HttpException(404, string.Format("No Controller Type: {0} Found For Path {1}", controllerType.FullName, context.HttpContext.Request.Path)); } public override void ReleaseController(IController controller) { } } }
The code basically tries to resolve the controller from our IoC container. If no controller is found – a 404 exception is thrown.
The Pipeline !
So the last step is to register a pipeline that is going to replace the default controller factory with the Autofac Controller Factory. The code for the pipeline looks like this:
using System.Web.Mvc; using Autofac.Integration.Mvc; using AutofacDependancyResolver.DependancyResolution.AutoFac.Factory; using Sitecore.Pipelines; namespace AutofacDependancyResolver.DependancyResolution.AutoFac.Pipelines { public class InitializeAutofacControllerFactory { public virtual void Process(PipelineArgs args) { SetControllerFactory(args); } private void SetControllerFactory(PipelineArgs args) { var containerFactory = new AutofacContainerFactory(); var container = containerFactory.Create(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); var controllerFactory = new AutofacControllerFactory(container); ControllerBuilder.Current.SetControllerFactory(controllerFactory); } } }
So the default controller factory is set to our controller factory ! Now the only thing remaining is to replace the pipeline with our own ! The configuration should be similar to:
<?xml version="1.0"?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <pipelines> <initialize> <processor type="AutofacDependancyResolver.DependancyResolution.AutoFac.Pipelines.InitializeAutofacControllerFactory, AutofacDependancyResolver.DependancyResolution" patch:before="*[@type='Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc']" /> <processor type="Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc"> <patch:delete /> </processor> </initialize> </pipelines> </sitecore> </configuration>
And that is it ! The Autofac resolving is ready to go ! 🙂
TL;DR;
You can find the example solution on Bitbucket !
Happy Injecting !
While I appreciate the attention, it was actually @Thomas_Stern who wrote that Ninject article 🙂