Suppose I have a class in which I want to sometimes* (but now always) intercept some (but not all) methods. The way I understand it, this can be done either with, say, InterceptAround()
in my Ninject module (in the higher-level code), or with an InterceptAttribute-derived attribute on those methods (at the implementation level).
I don't really like the first way of doing it, because it requires the consumer to know the details, there'll be many classes with many methods. But I don't like the second way either, since I don't see how to disable (or, rather, not to enable) the interception, as the attribute is fused with the code.
Is there some known approach to solve this problem?
*: for the lifetime of the application.
It sounds as though you are referring to an ordinary dynamic interceptor, which is how the Ninject Interception extension works by default.
Here's an example of a conditional interception:
class CustomInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (invocation.Request.Method.Name == "MethodToIntercept")
Console.WriteLine("Intercepted!");
invocation.Proceed();
}
}
You bind it directly to a single class like so:
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IFoo>().To<MyFoo>().Intercept().With<CustomInterceptor>();
}
}
And that's pretty much all you have to do if you want to dynamically intercept a single class.
The kernel extensions look promising because they let you write conditions directly into the declaration:
kernel.Intercept(ctx => ctx.Request.Service == typeof(IFoo))
.With<CustomInterceptor>();
However, this isn't particularly useful if you're trying to make decisions based on the method being executed, because this only gives you access to the binding context, and not the invocation. Mainly, this extension exists so that you can choose which classes or services (as opposed to methods) to intercept at runtime.
Better to stick to the binding syntax, and write the run-or-don't-run logic directly into the interceptor, as illustrated in the first example.
One important thing to note is that a dynamic interceptor will actually run for every (public / virtual) method on whichever class it is bound to, which can be very inefficient. Unfortunately, the Ninject Interception extension has to take a lowest-common-denominator approach because it is designed to support multiple proxy libraries. If you use Castle directly, you can use proxy generation hooks and interceptor selectors for fine-grained control, which is actually the recommended approach. As far as I can tell from the Ninject-DP2 source code, this is not supported with the Ninject extension.
Personally, I've never had a lot of success with the Ninject Interception extension for exactly this reason, and tend to stick to using Castle DP2 directly. However, if you're doing this on a small scale and aren't writing a performance-sensitive app, you should be fine writing dynamic interceptors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With