我有一个抽象的基类,它包含几个方法,其中一个我需要一直拦截。基类可以由用户定义的类继承,并在应用程序启动时向容器注册。如果用户尚未注册,则容器安装程序将自行注册一个。
问题在于 - 用户不必担心添加拦截器。容器应该自己添加它,无论注册组件的人和位置在哪里。
这就是我现在正在做的事情:
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,我开始使用它,直到我意识到我无法添加方法选择器。
答案 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>());