2

我在 Castle Windsor 中尝试拦截,并注意到拦截器似乎是作为我的服务接口的装饰器创建的。

换句话说,如果我有一个接口“ISomethingDoer”和一个具体的“ConcreteSomethingDoer”,代理会实现 ISomethingDoer,但不会从 ConcreteSomethingDoer 继承。

这很好,毫无疑问是设计使然,但我想知道我是否可以拦截公共接口不知道的具体类中的受保护虚拟方法。我这样做是为了添加日志记录支持,但我可能想记录一个类的一些特定内部细节。

在我有点缺乏想象力的测试用例中,我有这个:

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 示例中,我专门在注册中附加了一个记录器,而对于 Castle,我使用的是 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 的调用。

我可以看到温莎城堡为什么要这样做,但我想知道是否有办法调整行为?

(作为旁注,我不想使用 Windsor 自己的拦截器属性,因为我不想将依赖项引入到我的组合根之外的 Castle。)

我已经尝试专门解决 ConcreteSomethingDoer 并且这有效,但如果我正在解决 ISomethingDoer 则不行。

为这篇长文道歉,也很抱歉,因为我对温莎城堡很陌生!

4

1 回答 1

1

我可以像这样注册:

Container.Register(
    Component.For<ISomethingDoer, ConcreteSomethingDoer>()
    .ImplementedBy<ConcreteSomethingDoer>()
    .LifeStyle.Transient
);

这应该通过从 ConcreteSomethingDoer 派生来创建一个类代理。但是,这不适用于动态拦截器。但是,您可能可以通过创建一个在需要时注册拦截器的设施来解决这个问题。

于 2013-04-05T14:34:39.467 回答