Cross cutting concerns in EPiServer using Dynamic Proxies

Cross cutting concerns should be handled in an unobtrusive way, i.e. implemented in a way they don’t require any modifications to your original features.

One way to achieve this is by using Aspect Oriented Programming, more specifically using Castle Dynamic Proxies to intercept method calls at runtime with StructureMap.

The code examples below were implemented in an EPiServer Alloy MVC site.

In this example we’re going to add MiniProfiler and measure how long each method takes to run.

  1. First we create the class that will manage the interception:
namespace EPiServer.Templates.Alloy.Business
{
    using System;

    using Castle.DynamicProxy;

    public class EnrichmentOf<T> where T : IInterceptor, new()
    {
        private static readonly ProxyGenerator DynamicProxy = new ProxyGenerator();

        public static object ForInterface<TInterface>(object concrete)
        {
            return ForInterface(typeof(TInterface), concrete);
        }

        public static object ForInterface(Type iinterface, object concrete)
        {
            return DynamicProxy.CreateInterfaceProxyWithTarget(iinterface, concrete, new T());
        }

        public static object ForClass<TClass>(object concrete)
        {
            return ForClass(typeof(TClass), concrete);
        }

        public static object ForClass(Type cclass, object concrete)
        {
            return DynamicProxy.CreateClassProxyWithTarget(cclass, concrete, new T());
        }
    }
}
  1. Then we implement our interceptors. In this example we are going to add profiling and capture how long each method takes to run in the classes we’re intercepting using MiniProfiler.
namespace EPiServer.Templates.Alloy.Business
{
    using Castle.DynamicProxy;

    using StackExchange.Profiling;

    public class MiniProfilerInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            using (MiniProfiler.Current.Step(invocation.TargetType.Name + "." + invocation.MethodInvocationTarget.Name))
            {
                invocation.Proceed();
            }
        }
    }
}
  1. Now we are going to tell StructureMap to intercept all method calls in what we register in the container.
private static void ConfigureContainer(ConfigurationExpression container)
        {
            //Swap out the default ContentRenderer for our custom
            container.For<IContentRenderer>().Use<ErrorHandlingContentRenderer>().EnrichWith(EnrichmentOf<MiniProfilerInterceptor>.ForInterface<IContentRenderer>);
            container.For<ContentAreaRenderer>().Use<AlloyContentAreaRenderer>().EnrichWith(EnrichmentOf<MiniProfilerInterceptor>.ForClass<ContentAreaRenderer>);
            
            //Implementations for custom interfaces can be registered here.
        }

 

The result will be the MiniProfiler chiclet containing timings for all method calls of the services we registered, without modifying the original feature code.

Profiling is one example, other interceptors can be implemented for caching, logging for auditing purposes,

episerver-miniprofiler