I spent the whole day going around in circles attempting to fix an application that I broke. It’s not the first time, and I’m sure it won’t be the last.
It’s a pet application of mine that I work on from time to time to keep up to date with the latest Visual Studio and ASP.NET features. I thought it would be a good idea to upgrade from MVC 4 to 5, as a precursor to porting the solution across to Visual Studio 2015. So off I went half-cocked and installed the ASP.NET MVC 5.2.2 NuGet package, which in turn upgraded WebPages and Razor from version 2 to version 3. But in typical, if it ain’t broke then don’t fix it, style my application imploded and refused to compile. A couple of hours later and it was compiling, but Unity was no longer resolving dependencies even though the types were correctly registered in the container. Bottom line was that the version of Unity that I was using depended on version 2 of WebPages and Razor, and as such does not sit well with MVC 5. Once I had worked this out, I was able to upgrade Unity and all was well.
I did not really put a great deal of thought into the upgrade. If I had I would have realized that what I should be doing is porting the MVC 4 solution across to Visual Studio 2015 and then upgrading to MVC 5, whilst removing Unity completely. The reason being is that one of the neat features that will be introduced with ASP.NET 5 is out-of-the-box dependency injection. And out-of-the-box means no need to shoe-horn 3rd party packages/assemblies into the solution – unless you really want to.
What I’d like to demonstrate is the steps you need to take to implement Unity for constructor injection in an MVC 4 project, and how the ASP.NET 5 out-of-the-box dependency injection makes life a whole lot easier.
Implementing Unity in an MVC 4 project
Create a new ASP.NET MVC 4 and install the Unity Bootstrapper package
I’m using Visual Studio 2013 for this demo. If you have Visual Studio 2012 then the steps and outcomes should be the same, although I haven’t tested this. If you have Visual Studio 2010 SP1 then in theory you can download the MVC 4 framework. But it’s probably better to request an upgrade. Although I appreciate that this is not always possible given company and project constraints.
Create a new Visual C# ASP.NET project, and then instal the Unity Bootstrapper for ASP.NET MVC NuGet package –
The Unity Bookstrapper package adds 2 class libraries to the App_Start folder – UnityConfig.cs and UnityMvcActivator.cs –
The UnityMvcActivator class manages the life-time of the Unity container. It utilises the WebActivatorEx module to instantiate and configure the container during application start-up, and to dispose of the container during shut-down,
An alternative to using WebActivatorEx is to modify the Global.asax Application_Start and Application_End events to instantiate and dispose of the container. However, NuGet cannot do this automatically. It is something you would have to code manually.
The Start() method is executed during application start-up. The key point to getting Unity up and running is that UnityWebActivator calls the UnityConfig.GetConfiguredContainer() method to get a configured Unity container to use when resolving dependencies. We need to tell the system how to resolve the dependencies. We do this by registering the types – which we will do next.
The GetConfiguredContainer() method returns an instantiated Unity container that includes the details of which concrete types to instantiate when it instantiates an object that requires the injection of an interface.
In the example code below I have registered ProductService as the concrete implementation of IProductService.
In the next section I will implement IProductService, and ProductService. I will then modify the HomeController to require IProductService to be injected into it’s constructor. And then show that the dependency injection is working as expected.
IProductService and ProductService
To keep things simple, the IProductService interface exposes a single method, WhoIAm(), which returns a string.
The ProductService class implements this method, returning “I am product service”.
Injecting IProductService into HomeController
I have modified HomeController as follows –
- Added _productService as a private field of type IProductService
- Added a constructor which receives an instance of IProductService, and assigns this instance to the _productService field.
- Modified the Index() method to return the result of the _productService.WhoIAm() call.
Running the Project
Running the project results in the following action result from the Home/Index method –
This proves that Unity is correctly injecting an instance of the concrete ProductService class into the HomeController constructor.
It’s as easy as that. And it gets even easier with ASP.NET 5 out-of-box dependency injection.
Implementing Dependency Injection in an ASP.NET 5 vNext MVC Project
For this example I’m going to boot up Visual Studio 2015 preview.
This time I’m going to create a new ASP.NET 5 vNext Starter Web project.
IProductService, ProductService, and HomeController changes
I created the same IProductService and ProductService classes. And injected the IProductService class into the HomeController’s constructor. So exactly the same code as before.
As an aside, check out the hints telling us how many references each class and method has. This is a by-product of another really neat vNext feature – dynamic compilation.
Register the ProductService Type
As the dependency injection is out-of-the-box we do not need to install and configure any packages. All we need to do is register our concrete types.
The Startup class has a ConfigureServices method. The runtime calls this method, and passes through an instance of a class which implements the Microsoft.Framework.DependencyInjection.IServiceCollection interface.
All we need to do register the ProductService type, with the instance of IServiceCollection, as the concrete implementation for IProductService –
And Bob’s your Uncle
So the out-of-the-box implementation works – as it’s name suggests – straight out-of-the-box, without the need to install additional dependencies, or create the code to manage the life-cycle of the dependency injection container. All that is required is for the concrete types to be registered.
One thing to note is that at the time of writing vNext only supports constructor injection. It does not support property setter or method call injection. Not that this is an issue for me, as I only ever use constructor injection.