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
- Install nuget
Ninject.MVC3
1 | Install-Package Ninject.MVC3 |
This gave me
1 | Ninject.3.2.0.0 |
“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.”
- This created
NinjectWebCommon
insideAPPNAME.App_Start
and inside itsRegisterServices
method I loaded up modules, these modules cohesively grouped the dependacies.
1 | /// <summary> |
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.
- Created these modules in
APPNAME.App_Start.Modules
1 | using Ninject.Modules; |
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 | .InSingletonScope() // same object for ever |
- This then allowed constructor injection as
IService1Client
for controllers inheriting fromController
.
Ninject WebApi
For reasons of hey why not?
this UI project also has an API. To continue to support it I did the following.
- Installed
Ninject.Web.WebApi
which gave me
1 | Ninject.3.2.0.0 -> Ninject.3.2.2.0 // compatibility bump |
- Inside the
CreateKernel
method I addedGlobalConfiguration.Configuration.DependencyResolver = new Ninject.Web.WebApi.NinjectDependencyResolver(kernel);
1 | /// <summary> |
This brought in a System.Web.Http
dependency.
- Added binding redirect for System.Web.Http, I used the publicKeyToken value from the other entries as they were all the same.
1 | <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.
- This then allowed constructor injection as
IService1Client
for controllers inheriting fromApiController
.
Life is better with dependency injection ❤️