Using IoC with Umbraco & MVC
The question was asked on my post yesterday about the upcoming Umbraco 4.10.0 release with MVC support and whether it is possible to use IoC/Dependency Injection with our implementation. The answer is definitely yes!
One of the decisions we’ve made for the code of Umbraco is to not use IoC in the core. This is not because we don’t like IoC (in fact I absolutely love it) but more because things start to get really messy when not 100% of your developers understand it and use it properly. Since Umbraco is open source there are developers from many walks of life committing code to the core and we’d rather not force a programming pattern on them. Additionally, if some developers don’t fully grasp this pattern this leads to strange and inconsistent code and even worse if developers don’t understand this pattern then sometimes IoC can be very difficult to debug.
This ultimately means things are better for you since we won’t get in the way with whatever IoC framework you choose.
Which frameworks can i use?
Theoretically you can use whatever IoC framework that you’d like, though I haven’t tested or even tried most of them I’m assuming if they are reasonable frameworks that work with MVC then you should be fine. I’m an Autofac fan and to be honest I’ve only dabbled in other frameworks so all examples in this post and documentation are based on Autofac. Since we don’t use any IoC, it also means that we are not specifying a DependencyResolver so you are free to set this to whatever you like (I’d assume that most IoC frameworks would integrate with MVC via the DependencyResolver).
How do i do it?
I chucked up some docs on github here which I’ll basically just reiterate on this post again with some more points. Assuming that you construct your IoC container in your global.asax, the first thing you’ll have to do is to create this class and make sure it inherits from the Umbraco one (otherwise nothing will work). Then just override OnApplicationStarted and build up your container. Here’s an example (using Autofac):
/// <summary> /// The global.asax class /// </summary> public class MyApplication : Umbraco.Web.UmbracoApplication { protected override void OnApplicationStarted(object sender, EventArgs e) { base.OnApplicationStarted(sender, e); var builder = new ContainerBuilder(); //register all controllers found in this assembly builder.RegisterControllers(typeof(MyApplication).Assembly); //add custom class to the container as Transient instance builder.RegisterType<MyAwesomeContext>(); var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } }
Notice that I’ve also registered a custom class called MyAwesomeContext in to my container, this is just to show you that IoC is working. Of course you can do whatever you like with your own container :) Here’s the class:
public class MyAwesomeContext { public MyAwesomeContext() { MyId = Guid.NewGuid(); } public Guid MyId { get; private set; } }
Next we’ll whip up a custom controller to hijack all routes for any content item that is of a Document Type called ‘Home’ (there’s documentation on github about hijacking routes too):
public class HomeController : RenderMvcController { private readonly MyAwesomeContext _myAwesome; public HomeController(MyAwesomeContext myAwesome) { _myAwesome = myAwesome; } public override ActionResult Index(Umbraco.Web.Models.RenderModel model) { //get the current template name var template = this.ControllerContext.RouteData.Values["action"].ToString(); //return the view with the model as the id of the custom class return View(template, _myAwesome.MyId); } }
In the above controller, a new instance of MyAwesomeContext will be injected into the constructor, in the Index action we’re going to return the view that matches the currently routed template and set the model of the view to the id of the custom MyAwesomeContext object (This is just an example, you’d probably do something much more useful than this).
We can also do something similar with SurfaceControllers (or any controller you like):
public class MyTestSurfaceController : SurfaceController { private readonly MyAwesomeContext _myAwesome; public MyTestSurfaceController(MyAwesomeContext myAwesome) { _myAwesome = myAwesome; } [ChildActionOnly] public ActionResult HelloWorld() { return Content("Hello World! Here is my id " + _myAwesome.MyId); } }
That’s it?
Yup, these are just examples of creating controllers with IoC, the actual IoC setup is super easy and should pretty much work out of the box with whatever IoC framework you choose. However, you should probably read the ‘Things to note’ in the documentation in case your IoC engine of choice does something wacky with the controller factory.