Dependency Injection with ASP MVC 3–Distilled and Simplified | John V. Petersen

:

One of the key new features in the ASP MVC 3 framework is how the framework interacts with your Inversion of Control (IoC) Container. Note: the specific behavior of the IoC containers themselves has not changed. The only thing that has changed is how the MVC 3 framework interacts with the IoC Container.

Right off the bat, I want to give a big shout out to fellow MVP and ASPInsider Steve Smith for his very helpful post. I also want to acknowledge Brad Wilson’s helpful posts. These posts were very helpful to me and served as an inspiration to this series of posts on my blog. I also want to acknowledge a comment by Jeremy Miller on Steve’s blog wherein he chimed in on the semantics of GetInstance. Basically, whomever Steve acknowledged , I acknowledge here!! :)

In MVC 1 and 2, we had to create our own Custom Controller Factory. In MVC 3, your still free to do so. However, when you see how MVC 3 generically works with IoC containers, when upgrading to MVC 3, you will likely want to re-work your code!

Introducing the DependencyResolver Class

The DependencyResolver is a member of the System.Web.Mvc NameSpace and its job is quite simple: to provide a central registration point for your chosen IoC Container. Prior to MVC 3, we often dealt with our chosen IoC container directly. In MVC 3, there is an abstraction layer (the DependencyResolver Class) that we will interact with directly. Whether your chosen IoC Container is Windsor, StructureMap or Unity, you can take advantage of this new feature.

It’s all about conforming to the IDependencyResolver Interface

In order to register a dependency resolver, you must use a class that implements the IDepedencyResolver Interface – which itself, is quite simple:

IDependencyResolver Interface

  1. public object GetService(Type serviceType)
  2.  
  3. public IEnumerable<object> GetServices(Type serviceType)

The idea is simple – MVC needs interface to interact with. There are many IoC providers available and its not realistic nor desirable to expect that all of the providers would alter their implementations to some common specification. All we need to do to fill the gap is construct custom IDependencyResolver classes for our chosen IoC Containers.

Implementing StructureMap and Unity IoC Containers

The following classes provide the functionality we need for StructureMap and Unity:

StructureMap Resolver

  1. public class StructureMapDependencyResolver : IDependencyResolver
  2.     {
  3.        IContainer _container;
  4.  
  5.     public StructureMapDependencyResolver(IContainer container)
  6.         {
  7.             _container = container;
  8.         }
  9.  
  10.  
  11.         public object GetService(Type serviceType)
  12.         {
  13.             object instance = _container.TryGetInstance(serviceType);
  14.  
  15.             if (instance == null && !serviceType.IsAbstract)
  16.             {
  17.                 _container.Configure(c => c.AddType(serviceType, serviceType));
  18.                 instance = _container.TryGetInstance(serviceType);
  19.             }
  20.  
  21.             return instance;
  22.         }
  23.  
  24.     public IEnumerable<object> GetServices(Type serviceType)
  25.         {
  26.             return _container.GetAllInstances(serviceType).Cast<object>();
  27.         }
  28.     }

 

Unity Resolver

  1. public class UnityDependencyResolver : IDependencyResolver
  2. {
  3.     IUnityContainer _container;
  4.  
  5.     public UnityDependencyResolver(IUnityContainer container)
  6.     {
  7.         _container = container;
  8.     }
  9.  
  10.     public object GetService(Type serviceType)
  11.     {
  12.         object instance;
  13.         try
  14.         {
  15.             instance = _container.Resolve(serviceType);
  16.             if (serviceType.IsAbstract || serviceType.IsInterface)
  17.             {
  18.                 return null;
  19.             }
  20.             return instance;
  21.         }
  22.         catch (Exception e)
  23.         {
  24.             return null;
  25.         }
  26.     }
  27.  
  28.     public IEnumerable<object> GetServices(Type serviceType)
  29.     {
  30.         return _container.ResolveAll(serviceType);
  31.     }
  32. }

With our resolver classes in place, we can now set about the task of implementing them.

StructureMap Setup

  1. public class StructureMapContainerSetup
  2. {
  3.     public static void SetUp()
  4.     {
  5.  
  6.         IContainer container = new Container(
  7.                 x =>
  8.                 {
  9.                     x.For<SomeService>().
  10.                         Use<SomeService>().
  11.                         WithCtorArg(“stringResponse”).
  12.                         EqualTo(“IoC Container: StructureMap.”);
  13.  
  14.                     x.For<HomeController>().Use<HomeController>();
  15.                 });
  16.         DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
  17.     }
  18.  
  19. }

 

Unity Setup

  1. public class UnityContainerSetup
  2. {
  3.     public static void SetUp()
  4.     {
  5.         var container = new UnityContainer();
  6.  
  7.         container
  8.             .RegisterType<SomeService, SomeService>().
  9.             Configure<InjectedMembers>().ConfigureInjectionFor
  10.             <SomeService>(new InjectionConstructor(“IoC Container: Unity.”));
  11.  
  12.         container.RegisterType<HomeController, HomeController>();
  13.  
  14.         DependencyResolver.SetResolver(new UnityDependencyResolver(container));
  15.     }
  16. }

If you already use these IoC Containers, much of this code should be familiar. The process of setting up the containers. You can see each product’s syntax is slightly different. Regardless, it is clear that both containers are accomplishing the same task. When the Home Controller is requested, the Home Controller is return. When Some Service is requested, Some Service is returned, and in each case, a string is passed as a constructor argument. The following is the class definition for Some Service:

Some Service Class

  1. public class SomeService
  2. {
  3.     private string _stringResponse;
  4.     
  5.     public SomeService(string stringResponse)
  6.     {
  7.         _stringResponse = stringResponse;
  8.     }
  9.  
  10.     public override string ToString()
  11.     {
  12.         return _stringResponse;
  13.     }
  14.  
  15.     public void SetString(string stringResponse)
  16.     {
  17.         _stringResponse = stringResponse;
  18.     }
  19. }

Some Service is just a contrived class to demonstrate the these concepts. The following is the Home Controller:

Home Contoller

  1. public class HomeController : Controller
  2. {
  3.     protected SomeService _someService;
  4.  
  5.     public HomeController(SomeService someService)
  6.     {
  7.         _someService = someService;
  8.     }
  9.  
  10.     public ActionResult Index()
  11.     {
  12.         ViewBag.Message =  _someService.ToString();
  13.  
  14.         return View();
  15.     }
  16.  
  17.     public ActionResult About()
  18.     {
  19.         return View();
  20.     }
  21. }

This is the Home Controller, with a few modifications,  that is generated as part of a default ASP MVC Project. The HomeController takes on a dependency to SomeService which is supplied to the HomeController Constructor. In the Index Action, the ViewBag property is given a Message Property with a default value from SomeService.

As you would expect with any IoC Container, the SomeService instance will automatically be supplied when the HomeController is invoked.

All we have to do now is have the application wire-up the IoC Container. For this first example, we’ll use the Unity Container.

Application Start – with Unity

  1. protected void Application_Start()
  2. {
  3.     AreaRegistration.RegisterAllAreas();
  4.  
  5.     RegisterGlobalFilters(GlobalFilters.Filters);
  6.     RegisterRoutes(RouteTable.Routes);
  7.  
  8.     UnityContainerSetup.SetUp();
  9. }

And as we can see, it works!!

image

In the Application_Start, when we swap out UnityContainerSetup.SetUp() for StructureMapSetup.SetUp(), we get:

 

image

 

Just like that, we can easily swap out one IoC Container for another.

Using StructureMap as an example, let’s create a subclass of HomeController and have the IoC Container serve that up when an instance of HomeController is requested:

Modified StructureMap Setup

  1. IContainer container = new Container(
  2.         x =>
  3.         {
  4.             x.For<SomeService>().
  5.                 Use<SomeService>().
  6.                 WithCtorArg(“stringResponse”).
  7.                 EqualTo(“IoC Container: StructureMap.”);
  8.  
  9.             x.For<HomeController>().Use<HomeController2>();
  10.         });

Here is the code for HomeController2:

Home Controller 2

  1. public class HomeController2 : HomeController
  2. {
  3.     public HomeController2(SomeService someService) : base(someService)
  4.     {
  5.         _someService = someService;
  6.  
  7.         _someService.SetString(string.Format(“{0} Using Home Controller 2.”, _someService.ToString()));
  8.  
  9.     }
  10. }

All were doing here is slightly modifying the string that is returned by SomeService. With the IoC Container wired up, here’s what we get:

 

image

 

  Yes, it’s that easy!!

We can also use the DependencyResolver Object anywhere in our MVC app. For example, if in some other context, I needed an instance of SomeService:

var _service = DependencyResolver.Current.GetService<SomeService>();

The better integration with IoC/DI Containers in ASP MVC 3 is a nice feature. In the event you need to switch to a different container, that task becomes much easier because we  can use a generic interface to reference the container.