简体   繁体   English

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

[英]Castle Windsor apply interceptors with selector after component is already registered

I have an abstract base class which contains several methods, of which one I need to intercept at all times. 我有一个抽象的基类,它包含几个方法,其中一个我需要随时拦截。 The base class can be inherited by user defined classes and registered with the container on application startup. 基类可以由用户定义的类继承,并在应用程序启动时向容器注册。 In the event user hasn't registered one, the container installer will register one itself. 如果用户尚未注册,则容器安装程序将自行注册一个。

Here's the problem - the user should not have to worry about adding the interceptor. 这是问题 - 用户不必担心添加拦截器。 Container should add it on its own, regardless of who and where registered the component. 容器应该自己添加它,无论注册组件的人和位置。

This is what I'm doing now: 这就是我现在正在做的事情:

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

MyComponentMethodSelector is a simple IInterceptorSelector which checks whether the methodname equals the one I need to intercept (in which case a MyComponentMethodInterceptor gets added to it). MyComponentMethodSelector是一个简单的IInterceptorSelector,它检查methodname是否等于我需要拦截的那个(在这种情况下, MyComponentMethodInterceptor被添加到它)。

As you can see it will check whether the component is already registered first. 如您所见,它将检查组件是否已首先注册。

The question is - do I have a way of adding an interceptor if it IS already registered? 问题是 - 如果已经注册,我是否有办法添加拦截器? The most obvious choice that comes to mind is using an IContributeComponentModelConstruction , however at that point I will run into not being able to select the method which the interceptor gets added to. 想到的最明显的选择是使用IContributeComponentModelConstruction ,但是在那时我将无法选择拦截器添加到的方法。 Or is there? 还是有吗?

EDIT: 编辑:

I should have been a little more specific. 我本来应该更具体一点。 I need to add an interceptor for a specific method only. 我只需要为特定方法添加拦截器。 Hence why I'm using a MyComponentMethodSelector. 因此我为什么使用MyComponentMethodSelector。 I am aware of IContributeComponentModel, and I started out with that until I realised there was no way for me to add a method selector. 我知道IContributeComponentModel,我开始用它直到我意识到我无法添加方法选择器。

You can easily add configuration to a component with a ComponentModel construction contributor that is called at the construction of the component model for your service by implementing IContributeComponentModelConstruction . 您可以通过实现IContributeComponentModelConstruction轻松地将组件添加到具有ComponentModel构造参与者的组件,该构造参与者在构建服务的组件模型时IContributeComponentModelConstruction

Let's say you want to add an interceptor to any implementation of IEventuallyRegistered , and if the user didn't register a custom component you want to use DefaultRegistration : 假设您想要为IEventuallyRegistered任何实现添加拦截器,如果用户没有注册自定义组件, 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();
    }
}

Implementing the IContributeComponentModelConstruction interface lets you change the configuration of the component model when it is created: 通过实现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)));
        }
    }
}

Then add the component to the container before registering your component: 然后注册组件之前将组件添加到容器中:

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

Even though it is possible to do it through the ComponentRegistered event of the kernel with a facility, this is not recommended ; 尽管可以通过具有工具的内核的ComponentRegistered事件来执行此操作,但不建议这样做 ; since it was included in the original answer I'm including it but I'm pushing it down. 因为它包含在原始答案中,所以我将其包括在内但我正在推动它。 You would start by creating a facility 您将从创建工具开始

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)));
        }
    }
}

Then add the facility to the container before the registration of your component, or your facility will miss the event when registering your component: 然后在注册组件之前将工具添加到容器中,否则您的工具将在注册组件时错过该事件:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM