假设我有一个类,我希望有时*(但现在总是)拦截一些(但不是全部)方法。我理解它的方式,可以使用我的Ninject模块中的InterceptAround()
(在更高级别的代码中),或者使用这些方法上的InterceptAttribute派生属性(在实现级别)来完成。
我真的不喜欢第一种方式,因为它需要消费者知道细节,会有很多类有很多方法。但我也不喜欢第二种方式,因为我没有看到如何禁用(或者更确切地说,不启用)拦截,因为属性与代码融合。
是否有一些已知的方法可以解决这个问题?
*:用于应用程序的生命周期。
答案 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。但是,如果你是小规模地做这个并且没有编写对性能敏感的应用程序,你应该很好地编写动态拦截器。