Ninject MVC

I needed to add dependency injection to a old ASP.NET MVC (.Net 4.8) application. For reasons it did not have DI and used some glue to new up objects. Remember kids NEW IS GLUE and #trashington.

Dependency injection is an implementation of Dependency Inversion Principle (DIP). I knew how to use Ninject from previouse exposure but had never set it up from scatch. These are the steps I followed.

Ninject MVC3

  1. Install nuget Ninject.MVC3
1
Install-Package Ninject.MVC3

This gave me

1
2
3
4
5
Ninject.3.2.0.0
Ninject.MVC3.3.2.1.0
Ninject.Web.Common.3.2.0.0
Ninject.Web.Common.WebHost.3.2.0.0
WebActivatorEx.2.0 // this allows Ninject to use reflection on MVC controllers and hook into the pipeline

“WebActivatorEx -> A package that allows other packages to execute some startup code in web apps. This package should be used over the older WebActivator, which was not strong named.”

  1. This created NinjectWebCommon inside APPNAME.App_Start and inside its RegisterServices method I loaded up modules, these modules cohesively grouped the dependacies.
1
2
3
4
5
6
7
8
9
10
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Load(new ClientModule()); // this is a group of HTTP clients
kernel.Load(new ServiceModule()); // this is a group of internal services
kernel.Load(new FactoryModule()); // this is a group of... you guessed it factorys
}

Ninject can leverage refection and bind the default interface of the given types to the type. e.g. Foo : IFoo however Im not sure other libraries like Autofac or Unity can do this so I could then glue the setup to ninject and make it hard to later change.

Its simpler IMO to break these up by module and then resolve things manually so you know 100% what is being put into the dependency injection container and being made available to the application.

Additionally I have some notes here on where in the application Clients could live and what Factorys are.

  1. Created these modules in APPNAME.App_Start.Modules
1
2
3
4
5
6
7
8
9
10
11
12
13
using Ninject.Modules;

namespace APPNAME.App_Start.Modules
{
public class ClientModule : NinjectModule
{
public override void Load()
{
Bind<IService1Client>().To<Service1Client>();
Bind<IService2Client>().To<IService2Client>();
}
}
}

This will use transient scope (objects are always different) for each request.

Probably more of an opinion but I have always leaned towards starting with transient (objects are always different) and then moved over to scoped (objects are the same within a request, but different across different requests) or singleton (objects are the same for every object and every request) when it solved a problem or helped with performance.

The above is the same as typing Bind<IService1Client>().To<Service1Client>().InTransientScope() but is not needed.

You could use any of these methods from Ninject.Syntax

1
2
.InSingletonScope() // same object for ever
.InThreadScope() // same object in the request
  1. This then allowed constructor injection as IService1Client for controllers inheriting from Controller.

Ninject WebApi

For reasons of hey why not? this UI project also has an API. To continue to support it I did the following.

  1. Installed Ninject.Web.WebApi which gave me
1
2
Ninject.3.2.0.0 -> Ninject.3.2.2.0  // compatibility bump
Ninject.Web.WebApi.3.2.4.0
  1. Inside the CreateKernel method I added GlobalConfiguration.Configuration.DependencyResolver = new Ninject.Web.WebApi.NinjectDependencyResolver(kernel);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new Ninject.Web.WebApi.NinjectDependencyResolver(kernel);

return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}

This brought in a System.Web.Http dependency.

  1. Added binding redirect for System.Web.Http, I used the publicKeyToken value from the other entries as they were all the same.
1
2
3
4
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>

Multiple versions of the System.Web.Http assembly live in Global Assembly Cache (GAC), without this redirect when built we got version 3.2.1.0 which resulted in the error Could not load file or assembly 'System.Web.Http, Version=5.0.0.0 and sadness when people tried to use the application.

  1. This then allowed constructor injection as IService1Client for controllers inheriting from ApiController.

Life is better with dependency injection ❤️

References