|
The ASP.NET MVC framework is one of the coolest things to happen to ASP.NET since its creation. One of the things that I love about the MVC framework more than anything else is its flexibility. This flexibility allows it to be configured anyway the developer likes, including replacing the factory that creates controllers.
There are two main things that I wanted to accomplish with the Unity integration. The first was that I wanted my controllers to have the objects on which they depend injected into them in standard DI fashion. Secondly, I wanted the controllers themselves to be resolved through the IoC container rather than being tightly coupled by the routing rules. This would allow me to yank in and out different controller implementations if I need to (I figured this would come in quite handy for TDD and unit testing).
The first part is easy, just grab the Unity DLLs and reference them in your MVC project. At this point, you're now free to use Unity to inject whatever you feel like. Rigging up the controller factory so that it will use Unity to resolve controllers is equally easy because the mvc contrib codeplex site has already created a class called UnityControllerFactory that does just this. Once you've added references to Unity and Mvc.Contrib.Unity from your MVC project, you can change your global.asax.cs file to look something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using MvcContrib.Unity;
using Microsoft.Practices.Unity;
using UlyssesAgenda.Controllers;
using System.Web.Security;
namespace UlyssesAgenda
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class UlyssesApplication : HttpApplication, IUnityContainerAccessor
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{filename}.ico"); // IE8 requests this and it tries to hit a controller for it.
//routes.IgnoreRoute("{filename}.png");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start()
{
InitializeContainer();
RegisterRoutes(RouteTable.Routes);
}
protected virtual void InitializeContainer()
{
if (_container == null)
{
_container = new UnityContainer();
ControllerBuilder.Current.SetControllerFactory(typeof(UnityControllerFactory));
_container.RegisterType(typeof(HomeController), typeof(HomeController));
_container.RegisterInstance(typeof(AccountController), new AccountController());
}
}
#region IUnityContainerAccessor Members
private static UnityContainer _container;
public static IUnityContainer Container
{
get { return _container; }
}
IUnityContainer IUnityContainerAccessor.Container
{
get { return Container; }
}
#endregion
}
}
You'll notice that I mapped the HomeController type and allowed Unity to manage the instantiation of it. However, with AccountController I created my own instance. The main reason for this is that account controller relies directly upon a service which relies upon a SqlMembershipProvider instance. If I attempt to constructor-inject the AccountController, I get stuck in a quagmire where I have to register my own instances of SqlMembershipProvider and SqlProfileProvider and much more - and that removes the flexibility I get from defining that stuff in the Web.config file (and potentially breaks other ASP.NET functionality by not having it in that file).. So (just this once!) I am allowing the AccountController to be a manually created instance that is injected by Unity.
Next, I'll be posting about how to convert the default Unit Tests for the AccountController into tests that use Moq rather than hand-mocked POCOs.
Why would you want to do this? What is the use case for wanting your own
controller factory? It has already started causing problems, i.e.
membership etc - what was your reasoning? :)
I don't really have to explain why Inversion of Control and Dependency
Injection is a good thing, do I?? :)
Yup .. seriously - I love keeping things simple and so to me IoC and DI is
abstraction on steroids and only java developers should use it ;-) Seems
like engineering for the sake of engineering or maybe I'm thick :P
Kevin,
how are u handling lifetime of the controllers. The default is transient
lifetime manager. Is that sufficient for asp.net mvc?
I've just added this project to codeplex: http://mvcunity.codeplex.com/