Dependency Injection in ASP.NET MVC NerdDinner App using Ninject
In this post, I am applying Dependency Injection to the
NerdDinner application using Ninject. The controllers of
NerdDinner application have Dependency Injection enabled
constructors. So we can apply Dependency Injection through
constructor without change any existing code. A Dependency
Injection framework injects the dependencies into a class
when the dependencies are needed. Dependency Injection
enables looser coupling between classes and their
dependencies and provides better testability of an
application and it removes the need for clients to know
about their dependencies and how to create them. If you are
not familiar with Dependency Injection and Inversion of
Control (IoC), read Martin Fowler’s article
Inversion of Control Containers and the Dependency
Injection pattern.
The Open Source Project
NerDinner
is a great resource for learning ASP.NET MVC. A free
eBook
provides an end-to-end walkthrough of building
NerdDinner.com application. The free eBook and the Open
Source Nerddinner application are extremely useful if anyone
is trying to lean ASP.NET MVC. The first release of
Nerddinner was as a sample for the first chapter of
Professional ASP.NET MVC 1.0. Currently the application is
updating to ASP.NET MVC 2 and you can get the latest source
from the source code tab of Nerddinner at
http://nerddinner.codeplex.com/SourceControl/list/changesets. I have taken the latest ASP.NET MVC 2 source code of the
application and applied Dependency Injection using Ninject
and Ninject extension Ninject.Web.Mvc.
Ninject & Ninject.Web.Mvc
Ninject is available at
http://github.com/ninject
and Ninject.Web.Mvc is available at
http://github.com/ninject/ninject.web.mvc
Ninject is a lightweight and a great dependency
injection framework for .NET. Ninject is a great choice of
dependency injection framework when building ASP.NET MVC
applications. Ninject.Web.Mvc is an extension for ninject
which providing integration with ASP.NET MVC.
Controller constructors and dependencies of NerdDinner
application
Listing 1 – Constructor of DinnersController
public DinnersController(IDinnerRepository repository) {
dinnerRepository = repository;
}
Listing 2 – Constrcutor of AccountController
public AccountController(IFormsAuthentication formsAuth, IMembershipService service) {
FormsAuth = formsAuth ?? new FormsAuthenticationService();
MembershipService = service ?? new AccountMembershipService();
}
Listing 3 – Constructor of AccountMembership –
Concrete class of IMembershipService
public AccountMembershipService(MembershipProvider provider) {
_provider = provider ?? Membership.Provider;
}
Dependencies of NerdDinner
DinnersController, RSVPController
SearchController and ServicesController have a dependency
with IDinnerRepositiry. The concrete implementation of
IDinnerRepositiry is DinnerRepositiry. AccountController has
dependencies with IFormsAuthentication and
IMembershipService. The concrete implementation of
IFormsAuthentication is FormsAuthenticationService and the
concrete implementation of IMembershipService is
AccountMembershipService. The AccountMembershipService has a
dependency with ASP.NET Membership Provider.
Dependency Injection in NerdDinner using Ninject
The below steps will configure Ninject to apply
controller injection in NerdDinner application.
Step 1 – Add reference for Ninject
Open the NerdDinner application and add
reference to Ninject.dll and Ninject.Web.Mvc.dll. Both are
available from
http://github.com/ninject
and
http://github.com/ninject/ninject.web.mvc
Step 2 – Extend HttpApplication with
NinjectHttpApplication
Ninject.Web.Mvc extension allows integration
between the Ninject and ASP.NET MVC. For this, you have to
extend your HttpApplication with NinjectHttpApplication.
Open the Global.asax.cs and inherit your MVC application
from NinjectHttpApplication instead of HttpApplication.
public class MvcApplication : NinjectHttpApplication
Then the Application_Start method should be replace
with OnApplicationStarted method. Inside the
OnApplicationStarted method, call the
RegisterAllControllersIn() method.
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MobileCapableWebFormViewEngine());
RegisterAllControllersIn(Assembly.GetExecutingAssembly());
}
The RegisterAllControllersIn method will enables to
activating all controllers through Ninject in the assembly
you have supplied .We are passing the current assembly as
parameter for RegisterAllControllersIn() method. Now we can
expose dependencies of controller constructors and
properties to request injections
Step 3 – Create Ninject Modules
We can configure your dependency injection
mapping information using Ninject Modules.Modules just need
to implement the INinjectModule interface, but most should
extend the NinjectModule class for simplicity.
internal class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IFormsAuthentication>().To<FormsAuthenticationService>();
Bind<IMembershipService>().To<AccountMembershipService>();
Bind<MembershipProvider>().ToConstant(Membership.Provider);
Bind<IDinnerRepository>().To<DinnerRepository>();
}
}
The above Binding inforamtion specified in the
Load method tells the Ninject container that, to inject
instance of DinnerRepositiry when there is a request for
IDinnerRepositiry and inject instance of
FormsAuthenticationService when there is a request for
IFormsAuthentication and inject instance of
AccountMembershipService when there is a request for
IMembershipService. The AccountMembershipService class has a
dependency with ASP.NET Membership provider. So we configure
that inject the instance of Membership Provider. When
configuring the binding information, you can specify the
object scope in you application.
There are four built-in scopes available in
Ninject:
- Transient - A new instance of the type will be created each time one is requested. (This is the default scope). Binding method is .InTransientScope()
- Singleton - Only a single instance of the type will be created, and the same instance will be returned for each subsequent request. Binding method is .InSingletonScope()
- Thread - One instance of the type will be created per thread. Binding method is .InThreadScope()
- Request - One instance of the type will be created per web request, and will be destroyed when the request ends. Binding method is .InRequestScope()
Step 4 – Configure the Ninject Kernel
Once you create NinjectModule, you load them
into a container called the kernel. To request an instance
of a type from Ninject, you call the Get() extension method.
We can configure the kernel, through the CreateKernel method
in the Global.asax.cs.
protected override IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new ServiceModule()
};
return new StandardKernel(modules);
}
Here we are loading the Ninject Module
(ServiceModule class created in the step 3) onto the
container called the kernel for performing dependency
injection.
Source Code
You can download
the source code from
http://nerddinneraddons.codeplex.com. I put the modified source code of NerdDinner app onto
CodePlex repository. The repository will update with more
add-ons for the NerdDinner application.