Applying Dependency Injection in ASP.NET MVC NerdDinner.com Application
ScottGu, Scott, Phil and Rob have announced a free ASP.NET MVC eBook and an open source ASP.NET MVC application Nerddinner.com. The free eBook is a single chapter of the Wrox’s upcoming title Professional ASP.NET MVC 1.0. The free eBook provides an end-to-end walkthrough of building NerdDinner.com application. The free eBook and the free Nerddinner application are extremely useful if anyone is trying to lean ASP.NET MVC. If you are a beginner to ASP.NET MVC, I highly recommend checking the eBook and the NerdDinner.com application. You can download the NerdDinner.com application from here.
In this post, I am applying Dependency Injection to the
NerdDinner.com application using Microsoft Unity Application
Block. I was looking through the NerdDinner code and
observed that controllers have Dependency Injection enabled
constructors. So I can apply Dependency Injection through
constructor injection 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. In this post, I am using Microsoft Unity Application
Block for performing Dependency Injection pattern. Please
check my blog post
ASP.NET MVC Tip: Dependency Injection with Unity
Application Block
that demonstrated how you can use the Unity Application
Block to perform Dependency Injection within an ASP.NET MVC
application.
In this demo, I am doing constructor
injection using Unity container. If a class instantiate
using the Resolve method of the Unity container has a
constructor that defines one or more dependencies on other
classes, the Unity container automatically creates the
dependent object instance specified in parameters of the
constructor
Controller constructors and dependencies of NerdDinner
application
Listing 1 – Constructor of DinnersController
41 public DinnersController(IDinnerRepository repository) {
42 dinnerRepository = repository;
43 }
Listing 2 – Constrcutor of AccountController
26 public AccountController(IFormsAuthentication formsAuth, IMembershipService service) {
27 FormsAuth = formsAuth ?? new FormsAuthenticationService();
28 MembershipService = service ?? new AccountMembershipService();
29 }
Listing 3 – Constructor of AccountMembership – Concrete class of IMembershipService
271
272 public AccountMembershipService(MembershipProvider provider) {
273 _provider = provider ?? Membership.Provider;
274 }
Dependencies of NerdDinner
DinnersController, RSVPController and
SearchController 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.
The below steps will configure Unity to perform constructor injection in NerdDinner application.
Step 1 – Add reference for Unity Application Block
Add a reference to
Microsoft.Practices.Unity.dll and
Microsoft.Practices.ObjectBuilder2.
You can download
Unity from
here. The Unity project is available in CodePlex at
http://www.codeplex.com/unity.
Step 2 – Custom LifetimeManager class
Unity provides the functionality to specify the
location of instance. This functionality is very useful for
the ASP.NET applications where we can store or cache the
container in the HttpContext, HttpSession or
HttpApplication. In this demo, I used to store the container
in current HttpContext. In the below code, I am creating a
custom lifetime manager to store container in the current
HttpContext.
1 using System;
2 using System.Web;
3 using Microsoft.Practices.Unity;
4
5 namespace NerdDinner.IoC {
6 public class HttpContextLifetimeManager<T> : LifetimeManager, IDisposable {
7 public override object GetValue() {
8 return HttpContext.Current.Items[typeof(T).AssemblyQualifiedName];
9 }
10 public override void RemoveValue() {
11 HttpContext.Current.Items.Remove(typeof(T).AssemblyQualifiedName);
12 }
13 public override void SetValue(object newValue) {
14 HttpContext.Current.Items[typeof(T).AssemblyQualifiedName] = newValue;
15 }
16 public void Dispose() {
17 RemoveValue();
18 }
19 }
20 }
Step 3 – Controller Factory for Unity
and Register Types for Injection
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Web.Mvc;
6 using System.Web.Security;
7 using System.Security.Principal;
8 using NerdDinner.Models;
9 using Microsoft.Practices.Unity;
10 using NerdDinner.Controllers;
11 namespace NerdDinner.IoC {
12 public class UnityControllerFactory : DefaultControllerFactory
13 {
14 IUnityContainer container;
15
16 public UnityControllerFactory(IUnityContainer container)
17 {
18 this.container = container;
19 }
20
21 protected override IController GetControllerInstance(Type controllerType)
22 {
23 try {
24 if (controllerType == null)
25 throw new ArgumentNullException("controllerType");
26
27 if (!typeof(IController).IsAssignableFrom(controllerType))
28 throw new ArgumentException(string.Format(
29 "Type requested is not a controller: {0}", controllerType.Name),
30 "controllerType");
31 return container.Resolve(controllerType) as IController;
32 }
33 catch { return null; }
34
35 }
36 public static void Configure() {
37 //create new instance of Unity Container
38 IUnityContainer container = new UnityContainer();
39 //Register dependencies
40 container.RegisterType<IFormsAuthentication, FormsAuthenticationService>();
41 container.RegisterType<IMembershipService,AccountMembershipService>();
42 container.RegisterInstance<MembershipProvider>(Membership.Provider);
43
44 //Inject DinnerRepository for contract IDinnerRepository
45 container.RegisterType<IDinnerRepository,
46 DinnerRepository>(new HttpContextLifetimeManager<IDinnerRepository>());
47 ControllerBuilder.Current.SetControllerFactory(
48 new UnityControllerFactory(container));
49 }
50 }
51 }
The controller factory is responsible for creating
controller instances.We extend the built in default
controller factory with our own factory for working Unity
with ASP.NET MVC.
The above Unity
configuration specified in the Configure method tells 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.
Step 4 – Modify Global.asax.cs for configure Unity
container
29 void Application_Start() {
30 RegisterRoutes(RouteTable.Routes);
31 UnityControllerFactory.Configure();
32 }
The above code will set the configuration for the Unity container when our ASP.NET MVC application is started.
The source code of the new added files can be download from
here