如何使用Ninject设置可选方法拦截?

时间:2011-08-12 12:41:48

标签: c# .net ninject aop ninject-interception

假设我有一个类,我希望有时*(但现在总是)拦截一些(但不是全部)方法。我理解它的方式,可以使用我的Ninject模块中的InterceptAround()(在更高级别的代码中),或者使用这些方法上的InterceptAttribute派生属性(在实现级别)来完成。

我真的不喜欢第一种方式,因为它需要消费者知道细节,会有很多类有很多方法。但我也不喜欢第二种方式,因为我没有看到如何禁用(或者更确切地说,不启用)拦截,因为属性与代码融合。

是否有一些已知的方法可以解决这个问题?


*:用于应用程序的生命周期。

1 个答案:

答案 0 :(得分:6)

听起来好像你指的是一个普通的动态拦截器,Ninject拦截扩展是默认工作的方式。

以下是条件拦截的示例:

class CustomInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        if (invocation.Request.Method.Name == "MethodToIntercept")
            Console.WriteLine("Intercepted!");
        invocation.Proceed();
    }
}

将它直接绑定到单个类,如下所示:

public class MyModule : NinjectModule
{
    public override void Load()
    {
        Bind<IFoo>().To<MyFoo>().Intercept().With<CustomInterceptor>();
    }
}

如果你想动态拦截一个类,那就是你要做的全部事情。

内核扩展看起来很有希望,因为它们允许你直接在声明中写条件:

kernel.Intercept(ctx => ctx.Request.Service == typeof(IFoo))
    .With<CustomInterceptor>();

但是,如果您尝试根据正在执行的方法做出决策,这不是特别有用,因为这只能让您访问绑定上下文,而不是调用。主要是,此扩展存在,以便您可以选择在运行时拦截哪些服务(而不是方法)。

最好坚持使用绑定语法,并将run-or-not-run逻辑直接写入拦截器,如第一个示例所示。

需要注意的一件重要事情是动态拦截器实际上会在每个(公共/虚拟)方法上运行它所绑定的任何类,这可能是非常低效的。不幸的是,Ninject Interception扩展必须采用最小公分母方法,因为它旨在支持多个代理库。如果你直接使用Castle,你可以use proxy generation hooks and interceptor selectors for fine-grained control,这实际上是推荐的方法。据我所知,从Ninject-DP2源代码可以看出,Ninject扩展不支持此功能。

就我个人而言,由于这个原因,我从未在Ninject Interception扩展中获得很多成功,并且倾向于直接使用Castle DP2。但是,如果你是小规模地做这个并且没有编写对性能敏感的应用程序,你应该很好地编写动态拦截器。