Interception in .NET – Part 2: Dynamic Interception

This is part two of a series of posts on interception in .NET. You can find the first part here.

Interception Targets

There are two possible targets for interception:

  • Types, such as classes or interfaces;
  • Instances of types.

Depending on the target, we can use different interception techniques.

Interception Techniques

In .NET, like in other OOP languages, we have the following interception techniques:

  • Virtual method interception: this is a type interception technique by which we subclass dynamically a target type – an interface or a class, since structures do not allow subclassing – and add method overrides for the methods we want to intercept. Of course, only virtual methods can be intercepted (abstract methods and interface methods are treated as virtual); the interceptor returns an instance of the dynamically generated subclass of the target type, which is treated exactly as if it were this target type;
  • Interface interception: an instance interception technique. There has to be an existing object for us to intercept, and it must implement one or more interfaces. We can intercept any method or property exposed by one of these interfaces; basically, the generated interceptor code sits between the exposed interface and the existing target;
  • Transparent proxy interception: another instance interception technique. The target types must either be interfaces or classes inheriting from MarshalByRefObject, one instance of which should exist. It is possible to intercept any interface methods or any method declared in the MarshalByRefObject-derived class; the interceptor acts as a proxy between the exposed interface or class and the actual object;
  • Context-bound object interception: this a .NET-specific interception technique for instance interception by which we can intercept any calls to objects of classes inheriting from ContextBoundObject. This one is not as generic as the others because we need to have our class inherit from ContextBoundObject, which we wouldn’t normally do, and add some boilerplate code.

Next

Next post will talk about static interception.

Interception in .NET – Part 1: Introduction

Update: see part two here.

Interception is the capability by which developers can inject behavior dynamically into existing methods or properties, before, after or instead of their execution. A common paradigm is Aspect-Oriented Programming (AOP), which postulates that we separate non-core, like cross-cutting concerns, from core functionality, and we apply these concerns automatically to our code; this way developers need only focus on implementing the business requirements. These cross-cutting concerns normally consist of logging, exception handling, caching, access control and the likes. An example: imagine you want any exception that might be thrown by your code to be logged somewhere; in this case, you can create an aspect to be applied to your methods that wraps each in a trycatch block and does something with the caught exception.

In .NET, as in other object-oriented languages (think Java), we have basically two kinds of interception:

  • Static: the assembly code is changed after it is built, a process called IL weaving;
  • Dynamic: changes are done as the application is running.

Some examples of dynamic frameworks that allow injecting interception at compile or runtime include Unity, Ninject, Spring.NET, Castle Windsor, LinFu, Autofac, LOOM.NET, Seasar, etc (as you can see, these are all Inversion of Control containers). Static (post-compilation) ones include Fody, SheepAspect, Mono.Cecil, and PostSharp. There are use cases for both kinds, so one does not really exclude the other. Static interception will probably be faster, but then the resulting assembly will not be exactly what you expect it to be – it has happened to me: the .PDB file would not match the .DLL, but it was my fault! Smile. In dynamic interception you get more control over the process and can even modify it at runtime.

How exactly aspects are applied to the code depends on the framework being used: some rely on attributes, others XML configuration, and others on fluent interfaces. In any case, the general idea is:

“For methods X, Y and Z, before/after/instead of actually executing it, do this instead”

On the next post, I am going to talk about the alternatives that exist for dynamic interception in .NET. Stay tuned!