Overview
In Part 1 we covered the basics of the extension and introduced the IInterceptor interface. Now we can move more in depth and look at the interceptor system composed of
- Custom Interceptors
- Interception via Attributes
With these, we can define a rich set of interception capabilities in our applications.
Custom Interceptors
The base of the binding interception is the very simple IInterceptor interface:
1 2 3 4 5 6 7 8 | |
The idea behind and IInterceptor is to take the place of some kind of action. This is very simple and makes creating an custom interceptor very easy. In order to do it properly, however, you must use the IInvocation object you are given. Below is the most basic interceptor that you can create which resumes execution of the real method.
1 2 3 4 5 6 7 | |
The invocation.Proceed() call is crucial! Since a call can have multiple interceptors, we need a way to hand off execution to the next downstream interceptor. The Proceed() call will either invoke the next interceptor in the chain, or invoke the target intercepted method if their are no more interceptors.
The extension currently ships with three interceptors
SimpleInterceptor
The SimpleInterceptor provides before and after execution hooks that you can override. We can create a simple timing interceptor by overriding the hooks and writing to the Trace object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
There is a lot more that can be done with the IInvocation object. You should really take a minute to look over the interface and see some of the information available. I have also included IProxyRequest as there is a lot of good information there accessible from IInvocation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
Given this information you can implement simple or more complex interceptors capable of utilizing a large amount of information to do the job.
ActionInterceptor
The ActionInterceptor takes an Action
1 2 | |
If you want a quick spike and don’t want to define a full interceptor, the ActionInterceptor is very handy.
Multiple Interceptors
You have seen how to attach interceptors via a static registry (IKernel extensions for specific methods) and attaching them using bindings. Now, what may have not been obvious, is that you can attach multiple interceptors to a given binding.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
We can also change the order in which the interceptors are executed:
1 2 3 4 5 6 7 8 9 10 11 12 | |
If you do not want to use the binding syntax to specify interceptors, you can use attributes to mark specific classes for interception. The [Intercept] attribute is an abstract attribute for you to extend and use on classes and methods. When a derived attribute is applied on a class, it will register interception on all virtual methods of that class. If you wish to disable interception for a particular method, you can apply the [DoNotIntercept] attribute. If you only want to intercept a particular method in a class, just apply the derived attribute to that single method.
You must extend the base [Intercept] attribute as it needs to know what interceptor to attach. You specify this by overriding the CreateInterceptor method. We can use the TimingInterceptor used previously to create a attribute and apply it to a simple class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | |
There is one other part of the interception attributes that is also supported from the binding configuration: Order. When you attach interception attributes, you can specify the order of the interceptor. You do not need to specify this in your custom attributes; it is handled by the injection system. All you have to do is specify the order in the attribute usage.
1 2 3 4 5 6 7 8 9 10 11 12 | |
One thing you may have noticed is that I used two different interceptor types. This is perfectly valid. All virtual calls of ObjectWithOrderedInterceptors will be counted. In addition, calls to Foo will also set a flag and the flag will be set before the count interceptor has a chance to run.
This can be important if you are trying to time calls with an interceptor; yes, the interception system is going to skew your results either way, but the amount you are over can vary drastically if your timing interceptor is first or last in the chain.
Conclusion
That pretty much covers the Ninject.Extensions.Interception interceptors. Using this foundation, you can create just about any type of interception scheme you can think of.