组件已经注册后,Castle Windsor应用拦截器和选择器

时间:2014-07-23 07:17:07

标签: c# .net castle-windsor aop interceptor

我有一个抽象的基类,它包含几个方法,其中一个我需要一直拦截。基类可以由用户定义的类继承,并在应用程序启动时向容器注册。如果用户尚未注册,则容器安装程序将自行注册一个。

问题在于 - 用户不必担心添加拦截器。容器应该自己添加它,无论注册组件的人和位置在哪里。

这就是我现在正在做的事情:

if(!container.Kernel.HasComponent(typeof(MyBaseComponent)))
    container.Register(Component.For<MyComponent>()
        .Interceptors(InterceptorReference
        .ForType<MyComponentMethodInterceptor>())
        .SelectedWith(new MyComponentMethodSelector()).AtIndex(1));

MyComponentMethodSelector是一个简单的IInterceptorSelector,用于检查methodname是否等于我需要拦截的那个(在这种情况下会添加MyComponentMethodInterceptor)。

如您所见,它将检查组件是否已首先注册。

问题是 - 如果已经注册,我是否有办法添加拦截器?想到的最明显的选择是使用IContributeComponentModelConstruction,但是在那时我将无法选择拦截器添加到的方法。或者有吗?

修改

我本来应该更具体一点。我只需要为特定方法添加拦截器。因此,为什么我使用MyComponentMethodSelector。我知道IContributeComponentModel,我开始使用它,直到我意识到我无法添加方法选择器。

1 个答案:

答案 0 :(得分:8)

您可以通过实施IContributeComponentModelConstruction轻松地将组件添加到具有ComponentModel构造参与者的组件,该构件参与者在构建服务的组件模型时调用。

我们假设您要为IEventuallyRegistered的任何实现添加拦截器,如果用户没有注册您要使用的自定义组件DefaultRegistration

public interface IEventuallyRegistered { void test(); }
public class DefaultRegistration : IEventuallyRegistered { public void test() { } }
public class EventuallyRegisteredInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation) { invocation.Proceed(); }
}

internal class Program
{
    private static void Main(string[] args)
    {
        var container = new Castle.Windsor.WindsorContainer();
        container.Register(Component.For<EventuallyRegisteredInterceptor>());
        container.Register(Component.For<IEventuallyRegistered>().ImplementedBy<DefaultRegistration>());
        // I'm not doing the optional registration, I just want to 
        // demonstrate upgrading a additional configuration

        var t = container.Resolve<IEventuallyRegistered>();
        t.test();
    }
}

实现IContributeComponentModelConstruction接口可让您在创建组件模型时更改其配置:

public class RequireInterception : IContributeComponentModelConstruction
{
    public void ProcessModel(IKernel kernel, ComponentModel model)
    {
        if (model.Services.Contains(typeof(IEventuallyRegistered)))
        {
            model.Interceptors.Add(new InterceptorReference(typeof(EventuallyRegisteredInterceptor)));
        }
    }
}

然后在注册组件之前将组件添加到容器中:

container.Kernel.ComponentModelBuilder.AddContributor(new RequireInterception());
container.Register(Component.For<IEventuallyRegistered>().ImplementedBy<DefaultRegistration>());

即使可以通过带有工具的内核的ComponentRegistered事件来执行此操作,也不建议这样做;因为它包含在原始答案中,我包括它,但是我把它推倒了。您将从创建设施开始

public class InterceptionFacility : AbstractFacility
{
    protected override void Init()
    {
        Kernel.ComponentRegistered += new Castle.MicroKernel.ComponentDataDelegate(Kernel_ComponentRegistration);
    }

    void Kernel_ComponentRegistration(string key, Castle.MicroKernel.IHandler handler)
    {
        if (typeof(IEventuallyRegistered).IsAssignableFrom(handler.ComponentModel.Implementation))
        {
            handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(EventuallyRegisteredInterceptor)));
        }
    }
}

然后在注册组件之前将工具添加到容器中,否则您的工厂将在注册组件时错过该事件:

container.AddFacility<InterceptionFacility>();
container.Register(Component.For<IEventuallyRegistered>().ImplementedBy<DefaultRegistration>());