Sunday, 9 September 2012

How to: Implement Dependency Injection in MVC 4 with Ninject

After creating mvc 4, the first thing I realised was there were slightly framework changes. Most significantly is inside the 'Global.asax.cs', which moves all the configuration setting registers into separate class files in the folder 'App_Start'. 

This actually prevents me from doing DI using 'Ninject.MVC3' in the way I used to implement in mvc 3. While Ninject package for mvc 4 is not out yet, I have to come up with an alternative solution. The following is the step by step guide.


1. Add 'Ninject.MVC3' package

You will see 'NinjectWebCommon.cs' file is generated inside 'App_Start' folder, which was meant to be part of package adding process.

2. Modify 'Global.asax.cs'


* Inherit 'MvcApplication' from 'NinjectHttpApplication' instead of 'HttpApplication'

* Implement 'OnApplicationStarted' method inherited from 'NinjectHttpApplication', and move all registers in 'Application_Start' this method to support the normal usage of those functions.
* Implement 'CreateKernel' method and register your own services.

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

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
        }
    }


    public class MvcApplication : NinjectHttpApplication
    {
        protected override void OnApplicationStarted()
        {
            base.OnApplicationStarted();

            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
        }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        protected override IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            RegisterServices(kernel);
            return kernel;
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<IFlorentinesService>().ToDefaultChannel();
        }
    }
}

3. Modify controller

Introduce service into controller constructor before consumption.


namespace MVC4.Controllers
{  
public class HomeController : Controller  
{      
private ITestService service;
        public HomeController(ITestService service)      
{          
this. service = service;      
}  
}
}

4. Delete 'NinjectWebCommon.cs'

By specifying client endpoint, the service injection is done.