Using Ninject in ASP.NET MVC

Ninject MVC extension

I wrote my first blog post about achieving dependency injection using Ninject right here, there we have discussed about some basic stuff and even tried a small sample. One of the nice things about Ninject is there are different extensions available along with the core assemblies to work with different frameworks. Ninject has extension to work with ASP.NET MVC framework as well. Along with the core assemblies we need to add assemblies Ninject.Web.Common and Ninject.Web.Mvc to use in MVC projects. Ninject.Web.Common is a common library for both web-forms and MVC. You can download the Ninject core and extensions from here.

We have two options to use Ninject MVC extensions in projects: one is adding the binaries directly to the projects and the other way is installing from NuGet Package Manager Console (Install-Package Ninject.MVC3). In this post we have used the first approach.

NinjectHttpApplication

The important thing we have to do as part of setup is deriving the MvcApplication class in Global.asax.cs from the abstract class NinjectHttpApplication(shown in the below listing) instead of the built-in HtppApplication class.

// Global.asax.cs
public class MvcApplication : NinjectHttpApplication
{

}

Listing 1. Deriving global application class from NinjectHttpApplication

The NinjectHttpApplication class of course derives from the HttpApplication. The important merit we gain by doing this is the Ninject extension takes care of injecting the dependencies to the controllers and filters.

public abstract class NinjectHttpApplication : HttpApplication, IHaveKernel
{
	protected NinjectHttpApplication();

	public void Application_End();

	public void Application_Start();

	protected abstract IKernel CreateKernel();

	public override void Init();

	protected virtual void OnApplicationStarted();

	protected virtual void OnApplicationStopped();
}

Listing 2. NinjectHttpApplication

The NinjectHttpApplication has an abstract method CreateKernel that every MVC application should implement to get the advantage of the extension. In the CreateKernel method basically we will create all the modules that binds the interfaces to concrete implementations and pass it to a kernel, the kernel is finally returned from the method that will be used by the framework to resolve the dependencies whenever required. It is the OnApplicationStarted method that we have to override to do the usual setup in MVC application like register routes, add filters etc.

Let say we have a simple controller WeatherController that returns the weather data for a single city or all cities based upon the input parameter. This controller class has a dependency with IWeatherDataRepository which feeds the controller with the necessary weather data.

public class WeatherController : Controller
{
	private readonly IWeatherDataRepository _weatherDataRepository;

	public WeatherController(IWeatherDataRepository weatherDataRepository)
	{
		_weatherDataRepository = weatherDataRepository;
	}

	public ActionResult Index(string city)
	{
		return View(_weatherDataRepository.Data(city));
	}
}

Listing 3. Injecting dependency through constructor in a controller

Without any help of IoC containers or custom controller factories the MVC framework will throw an exception when it tries to instantiate the WeatherController because it doesn’t have a parameterless constructor.

The Ninject MVC extension rectifies this problem by having implementing its own controller factory. To get the the benefit of that all we have to do is create module and register all the dependencies of the controllers with the concrete types. In simple cases when the application has less no. of controllers with less dependencies we can create directly register the types in the kernel object itself instead of creating multiple modules. But it is a good idea to create separate modules and pass all them to the kernel.

All the modules should derive from the abstract class NinjectModule and implement the Load method. As you guessed it is in the Load methods we bind the things up.

public class WeatherModule : NinjectModule
{
	public override void Load()
	{
		Bind<IWeatherDataRepository>().To<WeatherDataRepository>()
			.WithConstructorArgument("xmlFile", @"F:\Tryouts\Ninject.MVC\Ninject.MVC\_weather_data.xml");
	}
}

Listing 4. WeatherModule

Finally we have to register all the modules in the CreateKernel method in Global.asax.cs.

public class MvcApplication : NinjectHttpApplication
{
	public static void RegisterGlobalFilters(GlobalFilterCollection filters)
	{
		filters.Add(new HandleErrorAttribute());
	}
   
   public static void RegisterRoutes(RouteCollection routes)
   {
       routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
       routes.MapRoute(
           "Default", // Route name
           "{controller}/{action}/{id}", // URL with parameters
           new
           {
               controller = "Home",
               action = "Index",
               id = UrlParameter.Optional
           });
   }
   
   protected override IKernel CreateKernel()
   {
	   var modules = new NinjectModule[]{ new WeatherModule()	};		
       return new StandardKernel(modules);
   }
   
   protected override void OnApplicationStarted()
   {
       base.OnApplicationStarted();
 
       AreaRegistration.RegisterAllAreas();
       RegisterGlobalFilters(GlobalFilters.Filters);
       RegisterRoutes(RouteTable.Routes);
   }
}

Listing 5. Registering WeatherModule in Global.asax.cs

If you have dozens of modules in your application then instead of creating all of the modules and passing them to the kernel you can load all the modules in the assembly by a single call as below,

kernel.Load(Assembly.GetExecutingAssembly());

Listing 6. Auto-registering all the Ninject modules

Download Sample

blog comments powered by Disqus