5

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

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

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


*:在应用程序的整个生命周期内。

4

1 回答 1

6

听起来好像您指的是普通的动态拦截器,这就是 Ninject Interception 扩展默认的工作方式。

下面是一个条件拦截的例子:

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>();

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

最好坚持绑定语法,并将运行或不运行逻辑直接写入拦截器,如第一个示例所示。

需要注意的重要一点是,动态拦截器实际上将针对它绑定到的任何类上的每个(公共/虚拟)方法运行,这可能非常低效。不幸的是,Ninject Interception 扩展必须采用最低公分母方法,因为它旨在支持多个代理库。如果直接使用 Castle,可以使用代理生成钩子和拦截器选择器进行细粒度控制,这其实是推荐的做法。据我从 Ninject-DP2 源代码中可以看出,Ninject 扩展不支持此功能。

就个人而言,正是由于这个原因,我在 Ninject Interception 扩展方面从未取得过很大成功,并且倾向于坚持直接使用 Castle DP2。但是,如果您是在小范围内执行此操作并且不是在编写对性能敏感的应用程序,那么您应该很好地编写动态拦截器。

于 2011-08-14T20:07:55.620 回答