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