Ninject MVC extension
I wrote my first post about achieving dependency injection using Ninject right here, there we have discussed about some basic things and even tried a small sample.
In this article we are going to explore little more advanced stuff in Ninject. One of the nice thing 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 work with 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
instead of the built-in HtppApplication class. The NinjectHttpApplication class of course derives from the HttpApplication.
The important merit we gain by doing this is the 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();
}
The NinjectHttpApplication has an abstract method CreateKernel that every MVC application should implement to get the advantage of the extension.
In the abstract 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 wherever 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));
}
}
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.
In our case although there is only one controller with one dependency let's create a module in the belief the application will become big in future.
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");
}
}
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());