我正在Castle Windsor进行拦截实验,并注意到拦截器似乎是作为我的服务接口的装饰器创建的。换句话说,如果我有一个接口“ISomethingDoer”和一个具体的“ConcreteSomethingDoer”,代理实现ISomethingDoer但不从ConcreteSomethingDoer继承。使用Castle Windsor拦截具体实现(与服务相反)使用Castle Windsor
这是好的,毫无疑问的设计,但我想知道的是,我是否可以在我的具体类中拦截受保护的虚拟方法,这些方法不会被公共接口知道。我这样做是为了添加日志记录支持,但我可能想记录一些类的特定内部细节。
在我稍有想象力的测试用例我有这样的:
public interface ISomethingDoer
{
void DoSomething(int Count);
}
[Loggable]
public class ConcreteSomethingDoer : ISomethingDoer
{
public void DoSomething(int Count)
{
for (var A = 0; A < Count; A++)
{
DoThisThing(A);
}
}
[Loggable]
protected virtual void DoThisThing(int A)
{
("Doing a thing with " + A.ToString()).Dump();
}
}
所以我想要做的是日志调用“DoThisThing”,即使它不是接口的一部分。
我已经设法让Autofac中的这个工作。 (我创建这里Linqpad脚本:http://share.linqpad.net/frn5a2.linq),但正与温莎城堡挣扎(见http://share.linqpad.net/wn7877.linq)
在这两种情况下,我的拦截器是一样的,看起来像这样:
public class Logger : IInterceptor
{
public void Intercept(IInvocation Invocation)
{
String.Format("Calling method {0} on type {1} with parameters {2}",
Invocation.Method.Name,
Invocation.InvocationTarget.GetType().Name,
String.Join(", ", Invocation.Arguments.Select(a => (a ?? "*null*").ToString()).ToArray())).Dump();
Invocation.Proceed();
"Done".Dump();
}
}
我真正想要的要做的是说“任何具有[Loggable]属性的类,都应该使用日志拦截器”。在Autofac例如我已经明确地连接一个记录器进行登记,而与城堡我使用IModelInterceptorsSelector看起来像这样:
public class LoggerInterceptorSelector : IModelInterceptorsSelector
{
public bool HasInterceptors(ComponentModel Model)
{
return Model.Implementation.IsDefined(typeof(LoggableAttribute), true);
}
public InterceptorReference[] SelectInterceptors(ComponentModel Model, InterceptorReference[] Interceptors)
{
return new[]
{
InterceptorReference.ForType<Logger>()
};
}
}
最后,执行此所有的代码是:
var Container = new WindsorContainer();
Container.Register(
Component.For<Logger>().LifeStyle.Transient
);
Container.Kernel.ProxyFactory.AddInterceptorSelector(new LoggerInterceptorSelector());
Container.Register(
Component.For<ISomethingDoer>()
.ImplementedBy<ConcreteSomethingDoer>()
.LifeStyle.Transient
);
var Doer = Container.Resolve<ISomethingDoer>();
Doer.DoSomething(5);
运行时,我希望每次调用该方法时都会看到“使用参数x调用方法DoThisThing”。相反,我只接到对DoSomething记录的调用。
我可以看到为什么温莎城堡这样做,但我想知道是否有办法调整行为?
(作为一个侧面说明,我不希望使用温莎自己的拦截器属性,因为我不希望我的介绍根组成的外部依赖性城堡。)
我已经试过专门解决ConcreteSomethingDoer这是有效的,但如果我正在解决ISomethingDoer问题,则不行。
对于这篇较长的文章感到抱歉,同时也很抱歉,因为我对温莎城堡相当陌生!
啊,这是伟大的,作品一种享受 - 非常感谢你!我对此还是有点新鲜感,之前没有遇到类型转发......从我可以收集的这意味着“对于ISomethingDoer,使用与ConcreteSomethingDoer相同的注册”,然后它只向容器注册ConcreteSomethingDoer? (我也可以摆脱“.ImplementedBy”来使用自我注册,这也起作用)。 – John 2013-04-05 15:12:00
注册后,您可以通过ISomethingDoer或ConcreteSomethingDoer来解析ConcreteSomethingDoer。副作用是强制生成类代理。 – Marwijn 2013-04-07 11:30:44
的逗号分隔的有关条款语法简单转发的快捷方式 - 即以下应该工作,以及: Component.For() .ImplementedBy () 的.forward () –
Bermo
2014-03-10 02:01:17