Click here to Skip to main content
Click here to Skip to main content
Articles » Web Development » ASP.NET » General » Downloads
 
Add your own
alternative version

ASP.NET MVC controller action with Interceptor pattern

, 2 Oct 2012 CPOL
This article is to demonstrate interceptor pattern with MVC controller action, and so action can be intercepted in controller classes without using action filters.
MvcCallInterceptors_Source_Code_and_Demo-noexe.zip
MvcCallInterceptorsDemo
MvcCallInterceptors
bin
Controllers
Interceptors
MvcCallInterceptors.csproj.user
MVCInterceptorComponents.cd
Properties
MvcCallInterceptorsDemo
App_Data
ASPNETDB.MDF
aspnetdb_log.ldf
bin
Content
themes
base
images
ui-bg_flat_0_aaaaaa_40x100.png
ui-bg_flat_75_ffffff_40x100.png
ui-bg_glass_55_fbf9ee_1x400.png
ui-bg_glass_65_ffffff_1x400.png
ui-bg_glass_75_dadada_1x400.png
ui-bg_glass_75_e6e6e6_1x400.png
ui-bg_glass_95_fef1ec_1x400.png
ui-bg_highlight-soft_75_cccccc_1x100.png
ui-icons_222222_256x240.png
ui-icons_2e83ff_256x240.png
ui-icons_454545_256x240.png
ui-icons_888888_256x240.png
ui-icons_cd0a0a_256x240.png
Controllers
Global.asax
Models
MvcCallInterceptorsDemo.csproj.user
Properties
Scripts
Views
Account
Home
Shared
packages
EntityFramework.4.1.10331.0
EntityFramework.4.1.10331.0.nupkg
lib
jQuery.1.5.1
Content
Scripts
jQuery.1.5.1.nupkg
jQuery.UI.Combined.1.8.11
Content
Content
themes
base
images
ui-bg_flat_0_aaaaaa_40x100.png
ui-bg_flat_75_ffffff_40x100.png
ui-bg_glass_55_fbf9ee_1x400.png
ui-bg_glass_65_ffffff_1x400.png
ui-bg_glass_75_dadada_1x400.png
ui-bg_glass_75_e6e6e6_1x400.png
ui-bg_glass_95_fef1ec_1x400.png
ui-bg_highlight-soft_75_cccccc_1x100.png
ui-icons_222222_256x240.png
ui-icons_2e83ff_256x240.png
ui-icons_454545_256x240.png
ui-icons_888888_256x240.png
ui-icons_cd0a0a_256x240.png
Scripts
jQuery.UI.Combined.1.8.11.nupkg
jQuery.Validation.1.8.0
Content
Scripts
jQuery.Validation.1.8.0.nupkg
jQuery.vsdoc.1.5.1
Content
Scripts
jQuery.vsdoc.1.5.1.nupkg
Modernizr.1.7
Content
Scripts
Modernizr.1.7.nupkg
MvcCallInterceptors_Source_Code_and_Demo.zip
App_Data
EntityFramework.dll
MvcCallInterceptors.dll
MvcCallInterceptors.csproj.user
MVCInterceptorComponents.cd
obj
Debug
TempPE
ASPNETDB.MDF
aspnetdb_log.ldf
EntityFramework.dll
MvcCallInterceptors.dll
MvcCallInterceptorsDemo.dll
ui-bg_flat_0_aaaaaa_40x100.png
ui-bg_flat_75_ffffff_40x100.png
ui-bg_glass_55_fbf9ee_1x400.png
ui-bg_glass_65_ffffff_1x400.png
ui-bg_glass_75_dadada_1x400.png
ui-bg_glass_75_e6e6e6_1x400.png
ui-bg_glass_95_fef1ec_1x400.png
ui-bg_highlight-soft_75_cccccc_1x100.png
ui-icons_222222_256x240.png
ui-icons_2e83ff_256x240.png
ui-icons_454545_256x240.png
ui-icons_888888_256x240.png
ui-icons_cd0a0a_256x240.png
Global.asax
MvcCallInterceptorsDemo.csproj.user
obj
Debug
TempPE
EntityFramework.4.1.10331.0.nupkg
EntityFramework.dll
jQuery.1.5.1.nupkg
ui-bg_flat_0_aaaaaa_40x100.png
ui-bg_flat_75_ffffff_40x100.png
ui-bg_glass_55_fbf9ee_1x400.png
ui-bg_glass_65_ffffff_1x400.png
ui-bg_glass_75_dadada_1x400.png
ui-bg_glass_75_e6e6e6_1x400.png
ui-bg_glass_95_fef1ec_1x400.png
ui-bg_highlight-soft_75_cccccc_1x100.png
ui-icons_222222_256x240.png
ui-icons_2e83ff_256x240.png
ui-icons_454545_256x240.png
ui-icons_888888_256x240.png
ui-icons_cd0a0a_256x240.png
jQuery.UI.Combined.1.8.11.nupkg
jQuery.Validation.1.8.0.nupkg
jQuery.vsdoc.1.5.1.nupkg
Modernizr.1.7.nupkg
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
using System.Web.Mvc;
using MvcCallInterceptors.Controllers;

namespace MvcCallInterceptors.Interceptors
{
    /*
     * InterceptorsRegistry is a class which takes care of registration of interceptor methods, 
     * and get interceptors methods for a method call in the controller.
     */
    public sealed class InterceptorsRegistry
    {
        static Dictionary<string, List<ActionInterceptor>> Interceptors = new Dictionary<string, List<ActionInterceptor>>();

        /// <summary>
        /// This method registers all interceptor methods in the given class type which are decorated with ActionInterceptorAttribute.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static void RegisterInterceptors<T>() where T : IInterceptorMvcController
        {
            //Challenge to stop recursive call if they are there

            var interceptedByViewControllerType = typeof(T);
            var members = interceptedByViewControllerType.FindMembers(MemberTypes.Method,
            BindingFlags.Instance | BindingFlags.Public, new MemberFilter(SearchForInterceptorAttribute),
            typeof(ActionInterceptorAttribute));

            foreach (var member in members)
            {
                //Register either with 
                var attribute = member.GetCustomAttributes(typeof(ActionInterceptorAttribute), false)[0] as ActionInterceptorAttribute;
                var methodInfo = member as MethodInfo;
                // To restrict recursive calling this is the simplest way I found and ActionResult return type is kind of 
                // overhead to pass result to subsequent interceptors and convert to object again.
                if(methodInfo.ReturnType==typeof(ActionResult) || methodInfo.ReturnType.IsSubclassOf(typeof(ActionResult)))
                {
                    throw new Exception("ActionResult methods cannot be act as interceptor");
                }

                if (methodInfo.GetParameters().Length !=2 || methodInfo.GetParameters()[0].ParameterType!=typeof(InterceptorParasDictionary<string,object>) ||
                    methodInfo.GetParameters()[1].ParameterType != typeof(object))
                {
                    throw new Exception("Interceptor method should have only two parameters namely InterceptorParasDictionary<string,object> and object types");
                }
                var key = ((attribute.InterceptionForViewControllerType == null ? attribute.ViewName.ToString() : attribute.InterceptionForViewControllerType.FullName)
                        + ";" + attribute.ActionName).ToLower();

                // In one interceptor (or interceptor controller) class if somebody tries to register more than one methods as interceptors for one action method
                // of other controller then it's not possible, such kind of scenario should not be happened and can be restricted by registering interceptor methods 
                // by using one thing only i.e. either ViewName or InterceptionForViewController but not both.
                // And below condtion would take care of this.

                
                var actionInterceptor = new ActionInterceptor(interceptedByViewControllerType, attribute, member as MethodInfo);
                if (Interceptors.ContainsKey(key) && Interceptors[key].All((inc)=>inc.Equals(actionInterceptor)))
                {
                    throw new Exception(string.Format("Duplicate interceptor entry for action {0} in {1}.",attribute.ActionName,
                        attribute.InterceptionForViewControllerType==null?"View Name "+  attribute.ViewName : "Controller "+  attribute.InterceptionForViewControllerType.FullName ));
                }

                if (!Interceptors.ContainsKey(key) || Interceptors[key] == null)
                {
                    Interceptors[key] = new List<ActionInterceptor>();
                }

                Interceptors[key].Add(actionInterceptor);
            }
        }

        public static IEnumerable<ActionInterceptor> GetInterceptors(BaseMvcController controller, ActionDescriptor actionDescriptor)
        {
            var key1 = (controller.GetType().FullName + ";" + actionDescriptor.ActionName).ToLower();
            var key2 = (controller.ViewName + ";" + actionDescriptor.ActionName).ToLower();
            var result1 = new List<ActionInterceptor>();
            var result2 = new List<ActionInterceptor>();
            if (InterceptorsRegistry.Interceptors.ContainsKey(key1))
            {
                result1 = InterceptorsRegistry.Interceptors[key1];
            }
            if (InterceptorsRegistry.Interceptors.ContainsKey(key2))
            {
                result2 = InterceptorsRegistry.Interceptors[key2];
            }
            var commonCount = result1.Intersect(result2, new ActionInterceptorComparer()).Count();
            if (commonCount > 0)
            {
                throw new Exception("An Interceptor registered multiple times");
            }
            var result = result1.Union(result2, new ActionInterceptorComparer());

            return result;
        }

        private static bool SearchForInterceptorAttribute(MemberInfo objMemberInfo, Object objSearch)
        {
            // Compare the name of the member function with the filter criteria. 
            return objMemberInfo.GetCustomAttributes(typeof(ActionInterceptorAttribute), false).Length > 0;
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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

Share

About the Author

amargujrathi2006
Technical Lead
India India
Like to dream on long drive and falling asleep on short drive..!

| Advertise | Privacy | Mobile
Web02 | 2.8.141022.2 | Last Updated 2 Oct 2012
Article Copyright 2012 by amargujrathi2006
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid