使用Castle Windsor拦截具体实施(而不是服务)

时间:2013-04-04 11:20:02

标签: castle-windsor interceptor

我在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记录的调用。

我可以看到为什么Castle Windsor会这样做,但我想知道是否有办法调整行为?

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

我已经尝试专门解决了ConcreteSomethingDoer,但这是有效的,但如果我正在解析ISomethingDoer,那就不行了。

为长篇帖子道歉,并道歉,因为我对Castle Windsor很新!

1 个答案:

答案 0 :(得分:1)

我可以注册:

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

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