Using a Fluent Filters with an IoC container (ASP.NET MVC 2)

Using FluentFilters with Inversion of Control container is preferred rather than using the FluentFiltersBuilder. In this case, you can manage creation and lifetime of filter object and use Dependency Injection. To achieve this, you need to do several steps.
  1. Implement custom class which inherits FilterRegistry class and overrides GetFilterInstance method to resolve object by type instead of create new. This class will be used instead FluentFiltersBuilder for registering filters.
  2. Create a custom Controller Factory for supporting IoC container and registering it.
In this example used Unity Application Block as IoC container.

Create custom FilterRegistry class
// UnityFilterRegistry.cs
public class UnityFilterRegistry: FilterRegistry
{
    private readonly IUnityContainer _container;
    
    public UnityFilterRegistry(IUnityContainer container)
    {
        _container = container;
    }
    
    // Override method for add DI functionality for filters
    public override object GetFilterInstance(Type filterType)
    {
        return _container.Resolve(filterType);
    }
}

Specify FluentFilters.FluentFiltersActionInvoker for System.Web.Mvc.IActionInvoker that returned in response to a query for that type.
<!-- Unity.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <container name="Default">
      <!-- Core -->
      <register type="System.Web.Mvc.IActionInvoker, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
                mapTo="FluentFilters.FluentFiltersActionInvoker, FluentFilters">
        <lifetime type="singleton"/>
      </register>
      <!-- Services -->
      <!-- Repositories -->
    </container>
  </unity>
</configuration>

Create a custom Controller Factory
// UnityControllerFactory.cs
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Practices.Unity;

namespace Website.Core
{
    public class UnityControllerFactory : DefaultControllerFactory
    {
        private readonly IUnityContainer _container;

        public UnityControllerFactory(IUnityContainer container)
        {
            _container = container;
        }

        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            IController icontroller;

            if (controllerType == null)
            {
                throw new HttpException(404, String.Format("The controller for path '{0}' could not be found or it does not implement IController.",
                                        requestContext.HttpContext.Request.Path));
            }

            if (!typeof(IController).IsAssignableFrom(controllerType))
            {
                throw new ArgumentException(string.Format("Type requested is not a controller: {0}", controllerType.Name), "controllerType");
            }

            try
            {
                icontroller = _container.Resolve(controllerType) as IController; // Resolve controller
                var controller = icontroller as Controller;
                if (controller != null)
                {
                    // Set custom ActionInvoker
                    controller.ActionInvoker = _container.Resolve<IActionInvoker>();
                }
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException(String.Format("Error resolving controller {0}", controllerType.Name), ex);
            }

            return icontroller;
        }
    }
}

Register UnityControllerFactory and use UnityFilterRegistry for work with filters
// Global.asax
using System.Web.Mvc;
using System.Web.Routing;
using FluentFilters;
using FluentFilters.Criteria;
using Microsoft.Practices.Unity;
using Website.Core;
using Website.Core.Filters;

namespace Website
{
    public class MvcApplication : System.Web.HttpApplication
    {
        #region Properties

        /// <summary>
        /// Gets Unity container instance.
        /// </summary>
        /// <value>The container.</value>
        public IUnityContainer Container
        {
            get { return UnityContainerFactory.GetContainer(); }
        }

        #endregion

        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 = UrlParameter.Optional } // Parameter defaults
            );
        }

        private void RegisterFluentFilters()
        {
            // Use custom IFilterRegistry
            IFilterRegistry registry = Container.Resolve<UnityFilterRegistry>();

            // Register filters
            registry.Add<BrowserDetectionFilter>(c =>
            {
                c.Exclude(new ControllerFilterCriteria("Account"));
            });

            // Register IFilterRegistry in UnityContainer
            Container.RegisterInstance(registry);
        }

        private void RegisterControllerFactory()
        {
            ControllerBuilder.Current.SetControllerFactory(Container.Resolve<UnityControllerFactory>());
        }

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterRoutes(RouteTable.Routes);

            RegisterFluentFilters();

            RegisterControllerFactory();
        }
    }
}
Working example of application you can find in src\Samples\FluentFilters.Samples.IoC folder of source code.

Last edited Jan 30, 2011 at 8:22 PM by banguit, version 14

Comments

No comments yet.