Funqy ASP.NET MVC

Developer
Mar 9, 2009 at 8:54 PM
Edited Mar 9, 2009 at 8:56 PM

Just to make sure it could be done, I integrated Funq into a MVC project.  The project I chose was based on Stephen Walther’s Contact Manager sample from www.asp.net.  Turned out to be quite simple, with one detour.

 

In the global.asx file I needed to create the container and initialize it, my changes in bold:

 

using System.Web;

using System.Web.Mvc;

using System.Web.Routing;

using Funq;

using ContactManager.Controllers;

using ContactManager.Models;

 

namespace ContactManager

{

    // 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 container { get; private set; }

 

        public static void RegisterRoutes(RouteCollection routes)

        {

            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 

            routes.MapRoute("Home",

                "Home/{action}/{id}",

                new { controller = "Contact", action = "Index", id = ""// Parameter defaults

            );

 

            routes.MapRoute(

                "Default",                                              // Route name

                "{controller}/{action}/{id}",                           // URL with parameters

                new { controller = "Contact", action = "Index", id = ""// Parameter defaults

            );

 

        }

 

       protected void Application_Start()

        {

            RegisterRoutes(RouteTable.Routes);

            InitializeContainer();

            ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory());

        }

 

        private void InitializeContainer()

        {

            container = new Container();

 

            container.Register<IFormsAuthentication>(c => new FormsAuthenticationService());

            container.Register<IMembershipService>(c => new AccountMembershipService());

            container.Register<IController>("Account",

                c => new AccountController(c.Resolve<IFormsAuthentication>(), c.Resolve<IMembershipService>()))

                .ReusedWithin(ReuseScope.None)

                .OwnedBy(Owner.External);

 

            container.Register<IContactManagerService>(c => new ContactManagerService())

                .ReusedWithin(ReuseScope.None)

                .OwnedBy(Owner.External);

            container.Register<IController>("Contact", c => new ContactController(c.Resolve<IContactManagerService>()))

                .ReusedWithin(ReuseScope.None)

                .OwnedBy(Owner.External);

        }

 

To create the FunqControllerFactory, I first attempted to copy the design in the MvcContrib project which derives the controller from DefaultControllerFactory and overrides the GetControllerInstance method.  Unfortunately, this method is passed a parameter of type Type and Funq can not resolve a Type (yet).

So I derived FuncControllerFactory from IControllerFactory and overrode the CreateController method with is passed the name of the controller.  This works great with Funq.

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using Funq;

 

namespace ContactManager

{

    public class FunqControllerFactory : IControllerFactory

    {

        #region IControllerFactory Members

 

        public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)

        {

            return MvcApplication.container.ResolveNamed<IController>(controllerName);

        }

 

        public void ReleaseController(IController controller)

        {

            var disposable = controller as IDisposable;

 

            if (disposable != null)

            {

                disposable.Dispose();

            }

        }

 

        #endregion

    }

}

 

Coordinator
Mar 9, 2009 at 9:54 PM
You can resolve with a Type just using a bit of reflection:

var typeToResolve = // the type you got;

var method = container.GetType().GetMethods()
    .Where(m => m.Name == "Resolve" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1)
    .First();
var instance = method.MakeGenericMethod(typeToResolve).Invoke(container, null);

Developer
Mar 9, 2009 at 10:36 PM
Yes, but if I remember correctly, one of the goals of Funq was to eliminate the need for Reflection.  I think using the named registrations works very well.
Coordinator
Mar 9, 2009 at 11:47 PM
hehe... good point ;)