Click here to Skip to main content
Click here to Skip to main content

Using Munq IOC with ASP.NET MVC 2 Preview 2

, 23 Jan 2010
Rate this:
Please Sign up or sign in to vote.
In this article, I will walk through the modification of the default ASP.NET MVC 2 application to use the Munq IOC container.  This is a fairly simple process during which we will create a custom Controller Factory for the framework which you can use in

Overview

In this article, I will walk through the modification of the default ASP.NET MVC 2 application to use the Munq IOC container. This is a fairly simple process during which we will create a custom Controller Factory for the framework which you can use in other applications.

The previous article is available on my blog at Introduction to Munq IOC Container for ASP.NET or on The Code Project at Introduction to Munq IOC Container for ASP.NET. This article develops the base application from which we will examine the features of the Munq IOC in future articles.

Step 1: Create an MVC 2 project

Open Visual Studio and create a new MVC 2 application. Give it any name. I called mine FinalApp to distinguish it from the InitialApp I created as a reference.

Build the application and familiarize yourself with the login/register/logout functionality of the AccountController. Hint: login is available in the upper right of the page.

Step 2: Remove the dependencies in AccountController

The AccountController has two hard dependencies to concrete implementations to FormsAuthenticationService and AccountMembershipService as shown in the bold lines below.
    // This constructor is used by the MVC framework to instantiate the controller using
    // the default forms authentication and membership providers.

    public AccountController()
        : this(null, null)
    {
    }

    // This constructor is not used by the MVC framework but is instead provided for ease
    // of unit testing this type. See the comments at the end of this file for more
    // information.
    public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
    {
        FormsAuth = formsAuth ?? new FormsAuthenticationService();
        MembershipService = service ?? new AccountMembershipService();
    }

To ‘fix’ this you need to:

  1. Add a reference to the Munq.DI.dll.
  2. In the global.asax
    1. create an application level Container variable.
    2. Register the dependencies in the container on Application_Start
  3. Change the default constructor for AccountController to resolve the dependencies.
  4. Change the constructor with parameters to check for null arguments.

Registering and Resolving the Controllers will be handled later.

After steps 1 and 2, the global.asax should look like the listing below. Changes are highlighted.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Munq.DI;
using FinalApp.Controllers;

namespace FinalApp
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        public static Container IOC {get; private set;}
        
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                 new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );

        }

        protected void Application_Start()
        {
            IOC = new Container();
            RegisterInterfaces();
            RegisterRoutes(RouteTable.Routes);
        }

        private void RegisterInterfaces()
        {
            IOC.Register<IFormsAuthentication>( ioc => new AccountMembershipService()); 
            IOC.Register<IMembershipService>( ioc => new FormsAuthenticationService());
     }
}

After steps 3 and 4, the AccountController constructors should look like:

    [HandleError]
    public class AccountController : Controller
    {

        // This constructor is used by the MVC framework to instantiate the controller using
        // the default forms authentication and membership providers.
        public AccountController()
            : this(    MvcApplication.IOC.Resolve<IFormsAuthentication>(), 
              MvcApplication.IOC.Resolve<IMembershipService>())
        {
        }

        // This constructor is not used by the MVC framework but is instead provided for ease
        // of unit testing this type. See the comments at the end of this file for more
        // information.
        public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
        {
            // Validate the parameters
            if (formsAuth == null)
                throw new ArgumentNullException("formsAuth");
    
            if (service == null)
                throw new ArgumentNullException("service");
            
            // set the dependencies    
            FormsAuth = formsAuth;
            MembershipService = service;
        }
        ...

Now build and run the application. It should work as it did before we started.

Yes, it seems that we have done a lot of work to get the same functionality and traded two dependencies for a dependency on the IOC container. We will remove this dependency in the next step.

Step 3: Create an IOC aware ControllerFactory

In order to remove the dependency the controllers have on the IOC container, it is necessary to create a custom ControllerFactory. This ControllerFactory will use the IOC container to create the correct controller and resolve any constructor dependencies.

Since we will want to reuse this in future projects we will:

  1. Create a new class library project.
  2. Add references to Munq.DI, System.Web.MVC, and System.Web.Routing.
  3. Create the MunqControllerFactory class.
  4. Register the new Controller Factory and register the controllers.
  5. Remove the dependency on the Container from AccountController.
  6. Fix up the tests.

After steps 1-3 the project should look like:

clip_image001[4]

Because Munq can register factories by name, and Munq handles the caching of the factories and lookup performed by the DefaultControllerFactory class, we can derive a new MunqControllerFactory from the IControllerFactory interface. The one of the CreateController method’s parameters is the name of the controller, without the Controller suffix. This means we can register the controllers by name. The other method that needs to be written is the ReleaseController method, which disposes of the controller if required. This is shown below. Notice that the constructor take a Munq Container as a parameter.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;

using Munq.DI;

namespace Munq.MVC
{
    public class MunqControllerFactory : IControllerFactory
    {
        public Container IOC { get; private set; }

        public MunqControllerFactory(Container container)
        {
            IOC = container;
        }

        #region IControllerFactory Members

        public IController CreateController(RequestContext requestContext, string controllerName)
        {
            try
            {
                return IOC.Resolve<IController>(controllerName);
            }
            catch
            {
                return null;
            }
        }

        public void ReleaseController(IController controller)
        {
            var disposable = controller as IDisposable;

            if (disposable != null)
            {
                disposable.Dispose();
            }
        }

        #endregion
    }
}

The next step is to register the MunqControllerFactory as the default controller factory. Open up the global.asax and modify it as shown.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Munq.DI;
using Munq.MVC;
using FinalApp.Controllers;

namespace FinalApp
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        public static Container IOC { get; private set; }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );

        }

        protected void Application_Start()
        {
            InitializeIOC();
            RegisterRoutes(RouteTable.Routes);
        }

        private void InitializeIOC()
        {
            // Create the IOC container
            IOC = new Container();

            // Create the Default Factory
            var controllerFactory = new MunqControllerFactory(IOC);

            // set the controller factory
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);

            // Register the dependencies
            IOC.Register<>IFormsAuthentication>(ioc => new FormsAuthenticationService());
            IOC.Register<IMembershipService>(ioc => new AccountMembershipService());

            // Register the Controllers
            IOC.Register<IController>("Home", ioc => new HomeController());
            IOC.Register<IController>("Account",
                    ioc => new AccountController(ioc.Resolve<IFormsAuthentication>(),
                                                  ioc.Resolve<IMembershipService>())
            );
        }
    }
}

Now we are ready to remove the dependency on the IOC from the AccountController. This is as simple as removing the default constructor as it references the IOC container. The MunqControllerFactory and the Munq IOC handle all the work of resolving the dependencies for the remaining constructor. The start of the AccountController should look like

    ...
    [HandleError]
    public class AccountController : Controller
    {
        public AccountController(IFormsAuthentication formsAuth, IMembershipService service)
        {
            // Validate the parameters
            if (formsAuth == null)
                throw new ArgumentNullException("formsAuth");

            if (service == null)
                throw new ArgumentNullException("service");

            // set the dependencies    
            FormsAuth = formsAuth;
            MembershipService = service;
        }
    ...

The only thing left is to comment out the AccountController Unit Test which test the constructor we just removed.

...
        //[TestMethod]
        //public void ConstructorSetsPropertiesToDefaultValues()
        //{
        //    // Act
        //    AccountController controller = new AccountController();

        //    // Assert
        //    Assert.IsNotNull(controller.FormsAuth, "FormsAuth property is null.");
        //    Assert.IsNotNull(controller.MembershipService, "MembershipService property is null.");
        //}
...

Now you can build, run the tests and the application. We now have a platform where we can now demonstrate the different Lifetime Managers and how they can simplify state management for your application. That however is something for the next article. In the next set of articles, I will build a real-world application, what I haven’t decided so give me some ideas of what you would like to see.

Note: This version of the MunqControllerFactory does not support the Areas feature of MVC 2. This too will be corrected in a future article.

del.icio.us Tags: ,,,

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Matthew Dennis
Software Developer (Senior) The Code Project
Canada Canada
Matthew works on improving the performance and experience of the Code Project site for users, clients, and administrators.
 
Matthew has more years of software develeopment, QA and architecture experience under his belt than he likes to admit. He gradutated for the University of Waterloo with a B.Sc. in Electrical Engineering. He started out developing micro-processor based hardware and software including compilers and operating systems.
His current focus is on .NET web development including jQuery, Webforms, MVC, AJAX, and patterns and practices for creating better websites.
He is the author of the Munq IOC, the fastest ASP.NET focused IOC Container.
His non-programming passions include golf, pool, curling, reading and building stuff for the house.
Follow on   Twitter

Comments and Discussions

 
QuestionYou got my 5... PinmemberJun Du5-Dec-11 9:06 
AnswerRe: You got my 5... PinstaffMatthew Dennis5-Dec-11 9:13 
AnswerRe: You got my 5... PinstaffMatthew Dennis5-Dec-11 9:15 
QuestionRegister Controller? Pinmemberkwilder8-Feb-10 11:34 
AnswerRe: Register Controller? PinstaffMatthew Dennis2-Mar-10 17:42 
GeneralRe: Register Controller? Pinmemberkwilder3-Mar-10 5:51 
GeneralAwesome DI Pinmemberucin-shihab3-Jan-10 4:10 
GeneralNice work! Pinmemberjim.wilson@kcx.com16-Dec-09 12:19 
GeneralRe: Nice work! PinstaffMatthew Dennis17-Dec-09 7:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 23 Jan 2010
Article Copyright 2009 by Matthew Dennis
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid