September 8, 2013

Dependency Injection using Ninject in MVC 4

Today let's talk how to implement DI using the most popular IoC container Ninject in MVC 4, because it differs from the previous versions of framework.

Small recall: the dependency injection is a software design pattern, which allows us easily change hard-coded dependencies between interfaces and their implementations.

Problem statement: for example we have HomeController and GuestController classes, which tightly coupled to the HomeService class as on the image below.

Then if we want to replace the HomeService class, we have to make changes in the classes that are tightly-coupled to it. This is pretty easy in a small project, but it becomes a laborious and error-prone process in a real project, when we have much more dependencies between classes.
We can solve part of this problem using C# interfaces to abstract definition from its implementation. Let's add interface IHomeService on our scheme and see how it will change.
As you can notice directions of the arrows have been changed TO the interface from the HomeService class. It calls Inversion of Control (IoC), when modules make no assumptions about what other systems do but rely on their interfaces.
Ok, that's much better, but C# requires us to specify the implementation class for an interface during instantiation, because it needs to know which implementation class we want to use. Our goal with Ninject is to reach the point where we specify that we want to instantiate an implementation of the IHomeService interface, but the details of which implementation is required are not part of the code in the controllers.
Installing Ninject
The easiest way to install ninject is to use the integrated Visual Studio support for NuGet, which makes it easy to install a wide range of packages and keep them up to date. Right click on the project, then choose Manage NuGet Package for Solution to open NuGet package window. After it type Ninject in the search field as in example and click install.
That's it. NuGet will do all necessary stuff: download package, add reference and check updates if it is needed.

Create the Dependency Resolver
Before using Ninject we need to create custom dependency resolver first. By creating it, we ensure that Ninject is used whenever an object is going to be created. The MVC Framework has it own IoC container Unity and default resolver for it, but we chose Ninject for our purposes, so let's create NinjectDependencyResolver class for it.
using System;
using System.Collections.Generic;
using Ninject;
using System.Web.Mvc;

namespace Test.Infrastructure
{
    public class NinjectDependencyResolver : IDependencyResolver
    {
        private readonly IKernel _kernel;

        public NinjectDependencyResolver()
        {
            _kernel = new StandardKernel();
            AddBindings();
        }

        public object GetService(Type serviceType)
        {
            return _kernel.TryGet(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return _kernel.GetAll(serviceType);
        }

        private void AddBindings()
        {
            _kernel.Bind<IHomeService>().To<HomeService>();
        }
    }
}
In constructor we created an instance of a Ninject kernel, which is the object we will use to communicate with Ninject and request implementations of interfaces.
The MVC Framework will call the GetService or GetServices methods when it needs an instance of a class to service an incoming request. The job of a dependency resolver is to create that instance - a task that we fulfill by calling the Ninject TryGet and GetAll methods. The TryGet method returns null when there is no suitable binding, rather than throwing an exception. The GetAll method supports multiple bindings for a single type, which is used when there are several different service providers available. Our dependency resolver class is also where we have set up our Ninject bindings. In the AddBindings method, we use the Bind and To methods to set up the relationship between the interface and the implementation class.

Register the Dependency Resolver
We have to tell the MVC Framework that we want to use our own dependency resolver, which we do by modifying the Global.asax.cs file.
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
using Test.Infrastructure;

namespace Test
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            DependencyResolver.SetResolver(new NinjectDependencyResolver());
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
}

Adding Injection into Controller
The last thing we should done is to add some lines of the code to the controllers
using System.Web.Mvc;

namespace Test.Controllers
{
    public class HomeController : Controller
    {
        private readonly IHomeService _homeService;

        public HomeController(IHomeService homeService)
        {
            _homeService = homeService;
        }

        public ActionResult Index()
        {
            return View();
        }
    }
}
And do the same with GuestController. Hope you can do it yourself.
We just add an implementation of the IHomeService interface in a class constructor. We have not specified which implementation we want to work with (we have made it in our custom dependency resolver), and we have added an instance variable called _homeService that we can use to refer to the IHomeService we receive in the constructor throughout the controller class.