5

With Unity, I'm able to quickly add an attribute based interception like this

public sealed class MyCacheAttribute : HandlerAttribute, ICallHandler
{
   public override ICallHandler CreateHandler(IUnityContainer container)
   {
        return this;
   }

   public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
   {
      // grab from cache if I have it, otherwise call the intended method call..
   }
}

Then I register with Unity this way:

container.RegisterType<IPlanRepository, PlanRepository>(
    new ContainerControlledLifetimeManager(),
    new Interceptor<VirtualMethodInterceptor>(),
    new InterceptionBehavior<PolicyInjectionBehavior>());

In my repository code, I can selectively decorate certain methods to be cached (with attribute values that can be customized individually for each method) :

    [MyCache( Minutes = 5, CacheType = CacheType.Memory, Order = 100)]
    public virtual PlanInfo GetPlan(int id)
    {
        // call data store to get this plan;
    }

I'm exploring similar ways to do this in Simple Injector. From what I read and searched looks like only interface/type level interception is available. But I would love the option of decorating individual methods with this type of attribute controlled interception behavior. Any advise?

[Edit: moved Autofac to its own question to keep this question focused]

Community
  • 1
  • 1
Calvin
  • 1,153
  • 2
  • 14
  • 25
  • Asking for solutions for two different libraries in one question is not really practical and the question risks being closed as 'too broad'. Please update this question to target Autofac specifically and create an exact new question for Simple Injector. I will do my best to answer your Simple Injector question. – Steven Mar 10 '15 at 06:59
  • Thanks Steven. This question was modified for SimpleInjector only. – Calvin Mar 10 '15 at 16:47

1 Answers1

5

Simple Injector does not have out-of-the-box support for Dynamic Interception, because this doesn't fit its design principles, as explained here. Interception capabilities can be added however, for instance using Castle DynamicProxy as shown here. It should also be possible to use Unity's interception capabilities on top of Simple Injector, but I never tried this.

When using DynamicProxy however, you will have to separate your interceptor class from the attribute class. This is actually a much better practice, because this keeps your attributes passive and prevents forcing your code base from taking a dependency on the interception library.

When implementing this with DynamicProxy, it might look something like this:

public class MyCacheInterceptor : IInterceptor 
{   
    public void Intercept(IInvocation invocation) {
        var attribute = invocation.Method.GetAttribute<MyCacheAttribute>();

        if (attribute == null) {
            // Pass through without applying caching
            invocation.Proceed();
        } else {
           // apply caching here
        }
    }
}

Simple Injector however, promotes Aspect-Oriented Programming by applying SOLID principles and using decorators instead. In the applications I write I define generic abstractions such as ICommandHandler<TCommand> and IQueryHandler<TQuery, TResult>. This makes applying caching through decorators trivial. What's nice about decorators is that they are much cleaner (as they don't depend upon any external library) and are much more performant.

Steven
  • 166,672
  • 24
  • 332
  • 435
  • Thanks Steven. Nice ideas about decorators on generic interface. However our repository interfaces have to different from each other and this makes handwritten decorators a big task - that's why I'm looking for IoC interception features. My reservation with interface based interception is the performance overhead of each and every call in that interface being intercepted (plus a call to GetCustomAttribute). But maybe under the hood Unity's PolicyInjectionBehavior does the same. I really like the super fast performance of SimpleInjector and will give it a try on interception. – Calvin Mar 10 '15 at 20:48
  • @Calvin: If your repositories need to different from each other, you might be violating three out of 5 principles of SOLID. Take a good look at [this article](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92) for a detailed discission on this. – Steven Mar 10 '15 at 20:50
  • hi Steven, GetCustomAttribute() doesn't return my attribute in this case (always get null back). Per this thread http://stackoverflow.com/a/17241720/879655, due to the proxy, the custom attribute can't be accessed. Does the above code work for you? Thanks! – Calvin Mar 11 '15 at 21:27
  • @Steven is this answer still valid? – ilkerkaran May 08 '19 at 15:42
  • @ilkerkaran: Yes it is. Our philosophy hasn't changed and we still promote the use of decorator instead, but Castle DynamicProxy can still be applied as described above. – Steven May 08 '19 at 16:55