I would like to thank Rob Conery for posing the question:

rob_conery

As the project’s portal states:

MVC Turbine is a plugin for ASP.NET MVC that has IoC baked in and auto-wires controllers, binders, view engines, http modules, etc. that reside within your application. Thus you worry more about what your application should do, rather than how it should do it.

Let’s see how this plays out for your application…

Plain Old MVC Application

If you create an MVC application by using File –> New, you get the full power of the MVC framework but your application is not yet setup to take full advantage of it.  Say you want to take full advantage the separation of concerns that MVC provides but you’re using poor man’s dependency injection (DI) to work around the dependencies for your controllers:

   1: [HandleError]
   2: public class HomeController : Controller {
   3:     public IMessageService MessageService { get; set; }
   4:  
   5:     public HomeController() : this(new MessageService()) {
   6:     }
   7:  
   8:     public HomeController(IMessageService service) {
   9:         MessageService = service;
  10:     }
  11:  
  12:     public ActionResult Index() {
  13:         ViewData["Message"] = MessageService.GetDefaultMessage();
  14:  
  15:         return View();
  16:     }
  17:  
  18:     public ActionResult About() {
  19:         return View();
  20:     }
  21: }
  22:  
  23: public interface IMessageService {
  24:     string GetDefaultMessage();
  25: }
  26:  
  27: public class MessageService : IMessageService {
  28:     public string GetDefaultMessage() {
  29:         return "Welcome to ASP.NET MVC!";
  30:     }
  31: }

Although there is nothing wrong with using poor man’s DI as you start your application, you’ll quickly realize that a manually wiring up all dependencies across your application can be a rather tedious task. However, if you remove the poor man injection, aka remove the default constructor that provides the implementation, you’ll get the following error:

ctor_error This error is due to the fact that the DefaultControllerFactory that ships with the MVC framework, doesn’t support the resolution of dependencies for complex controllers. Not saying that it should, just stating the current implementation.

How do we fix this?

Fortunately, the MVC framework allows you to provide your own controller factory that can create controllers with complex needs. A sample implementation can be done like,

   1: // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
   2: // visit http://go.microsoft.com/?LinkId=9394801
   3:  
   4: public class MvcApplication : HttpApplication {
   5:     public static void RegisterRoutes(RouteCollection routes) {
   6:         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
   7:  
   8:         routes.MapRoute(
   9:             "Default", // Route name
  10:             "{controller}/{action}/{id}", // URL with parameters
  11:             new {controller = "Home", action = "Index", id = ""} // Parameter defaults
  12:             );
  13:     }
  14:  
  15:     protected void Application_Start() {
  16:         // Configure the runtime to use our controller factory.
  17:         var controllerFactory = new CustomControllerFactory();
  18:         ControllerBuilder.Current.SetControllerFactory(controllerFactory);
  19:  
  20:         RegisterRoutes(RouteTable.Routes);
  21:     }
  22: }
  23:  
  24: /// <summary>
  25: /// Our 'custom' controller factory
  26: /// </summary>
  27: public class CustomControllerFactory : DefaultControllerFactory {
  28:     protected override IController GetControllerInstance(Type controllerType) {
  29:         // Very simplistic, wire up the dependency here
  30:         if (controllerType == typeof (HomeController)) {
  31:             return new HomeController(new MessageService());
  32:         }
  33:  
  34:         // For all other controllers, have the default implementation
  35:         return base.GetControllerInstance(controllerType);
  36:     }
  37: }

The implementation, CustomControllerFactory, is pretty simple and not very usable for controllers that are not the HomeController. Also, you need know how the controller factory is wired into the runtime so the framework will know how to use it.  Although it’s not a lot of code, you’ll need to know how the MVC runtime works and interacts with the extensibility points.  Don’t get me wrong, if you’re learning MVC, this is a great way to get your hands deep into the code and really grok things.  If you’re a seasoned MVC developer, you’ve either done this several times, or have componentized this piece and re-use it across your applications.

Why MVC Turbine?

The whole purpose of MVC Turbine is to speed your MVC development by having the plug-in handle all churn of the runtime and allow you to focus on what your application needs to do, rather than how to do it.  Here’s a short list of what MVC Turbine does for you:

  • Provides a facade for your IoC container of choice (currently StructureMap, Castle Windsor/MicroKernel, Unity and Ninject).
  • Extensibility API to take advantage of the runtime.
  • Registers all MVC types (controllers, view engines, etc.) with the container.
  • Sets up the MVC extensibility points to use the registered components.
  • A lot more features…

Taking the example above and making it run on top of MVC Turbine, the code changes as follows (the controller code remains the same):

   1: public class DefaultMvcApplication : TurbineApplication {
   2:     static DefaultMvcApplication() {
   3:         //Tell MVC Turbine to use Castle Windsor as the default container
   4:         ServiceLocatorManager.SetLocatorProvider(() => new WindsorServiceLocator());
   5:     }
   6: }
   7:  
   8: // Use this marker interface to provide service registrations to MVC Turbine.
   9: public class DomainServiceRegistration : IServiceRegistration {
  10:     public void Register(IServiceLocator locator) {
  11:         // Tell the runtime to use MessageService for any request of IMessageService.
  12:         locator.Register<IMessageService, MessageService>();
  13:     }
  14: }

All the plumbing needed to resolve dependencies is handled by the Turbine runtime by leveraging the underlying container. So if you need to add another dependency to your controller, say IFooService, all you need to do is add the dependency to your controller and then register the type within the IServiceRegistration implementation.

Where to go from here?

If you’re interested on what MVC Turbine can provide to your application besides dependency resolution for your controllers, check out the download page for feature demos and sample applications.  Also, check out these blog posts that go deeper into the MVC Turbine runtime:

Happy coding!