Aop With castle - Part 2 - Selecting methods to intercept
Previous Part of the series
Part 1 – The basic of interception
Some people, after looking at interceptor concept, are not fully convinced that castle can support all concepts of AOP and the first question usually is: How can I choose witch method intercept, instead of intercepting calls to all methods, and how can I configure this with XML file or fluent configuration?. This answer can have various solutions, but in my opinion the simplest one is doing a little manual logic on interceptor.
Since the interceptor is resolved by castle it is possible to add a list of valid regular expressions used to select methods to intercept, and simply check the method name to decide if it needs to be intercepted. This approach is the most simple one because it is based only on the basic structure of castle, and it has the advantages of change the list of methods to intercept simply changing the configuration of the interceptor. You can put this code on an interceptor or create a base interceptor class that contains the base logic.
|
|
This is a simple example on how you can filter method to intercept, the CanIntercept() can be implemented in this way.
|
|
The only modification is during registration, because now you need to specify the list of regexes to identify methods that needs to be intercepted
|
|
This is really a simple solution, and you can verify from the output that only selected methods are intercepted.
In red I highlighted the calls to regex.Match(), and since they are a little bit expensive, to speedup execution we can add caching using a dictionary, to store result of methods already scanned, just to avoid using too much regex at each call; the basic concept is always the same:
|
|
I stored the result of the CanIntercept directly in a dictionary, and I use RuntimeMethodHandle just to save a little bit of memory not storing the full MethodInfo object. Then I modify the CanIntercept function in this way.
|
|
Now the same configuration produces this output.
As you can see the regex are called only for the first call of a method, each subsequent calls does not requires Regex.Match anymore.
And with this little trick I simply end with an interceptor that permits to select methods you want to intercept with configuration.
If you do not like doing this manually, Castle offers a native way to decide which method to intercept, based on the interface IInterceptorSelector, that contains a single method with this signature.
|
|
Basically it receives the Type and MethodInfo for the method being called, and a list of interceptors configured for that method, the purpose of the selector is to return an array containing only the interceptors that are allowed to be used on that method. A possible implementation is the following one.
|
|
This selector contains a dictionary of Type and List<String>, basically for each interceptor type it contains a list of regex to identify methods to be intercepted. The rest of the selector is really simple, with a little bit of LINQ we can select only the interceptors that are in the dictionary and have at least one match with the method name. You can use it in this way.
|
|
I created a selector that permits to select a couple of interceptors, one is the DumpInterceptor, and I want it to intercept the DoSomething method, while the LogInterceptor should intercept only the Augment method. Once the selector is configured you can simply use it in fluent configuration.
|
|
Now you can run the program and look at the output.
With red color I highlight the calls to the SelectInterceptors method, and you can immediately see that Castle does caching internally and does not call the SelectInterceptors() method more than once for each method, so we does not need to cache stuff. As you can see from the output the result is the one I expect, dumpInterceptor is intercepting only the method DoSomething while the LogInterceptor intercepts only the Augment.
You can use the approach you prefer.
Alk.