城堡温莎拦截方法从class级内召唤

我们在Castle Windsor容器中注册了组件,就像这样

void RegisterComponent() { var component = Component.For().ImplementedBy(); component.Interceptors(); container.Register(component); } 

然而,我们遇到的问题是,当我们从类中进行方法调用时,它不会被截获。 例如,我们有类似的组件

 ServiceA : IService { public void MethodA1() { // do some stuff } public void MethodA2() { MethodA1(); } } 

如果我们从其他类中调用MethodA2MethodA1方法,则会截获它,但是当从MethodA2调用时, MethodA1显然不会被截获,因为调用来自类中。

我们发现类似的情况,解决方案Castle Dynamic Proxy在从类中调用时不拦截方法调用但是该解决方案使用new运算符来创建组件和代理,这在我们的情况下不适合,因为我们使用容器。 我们可以像上面那样使用此解决方案进行组件注册 还是有其他方法来解决这个问题?

对于从MethodA2调用MethodA1时进行拦截,您需要使用基于inheritance的拦截(这是因为您使用this引用进行调用)。

要使基于inheritance的拦截成为可能,首先需要使MethodA1MethodA2 virtual

然后你可以像这样进行容器注册:

 container.Register(Component.For().Interceptors()); container.Register(Component.For().UsingFactoryMethod(c => c.Resolve())); 

首先将您的服务注册为自身应用拦截器(这将在服务上添加基于inheritance的拦截)。 然后,您可以注册将使用先前注册的服务的接口。

将您的注册更改为以下内容,Windsor应切换到类代理 – 即使用inheritance进行拦截,而不是组合。

 void RegisterComponent() { container.Register(Component.For().ImplementedBy().Interceptors()); } 

我们使用CreateClassProxy方法为服务创建代理,因为它是在回答问题时提出的,因为城堡动态代理在从类中调用时不拦截方法调用 。 然后我们将获得的代理注册为接口的实现。 所以我们的自定义RegisterComponent方法看起来像这样

 private void RegisterComponent() where TInterface : class where TImplementation : class, TInterface { var proxyType = new ProxyGenerator().CreateClassProxy().GetType(); Container.Register(Component.For().ImplementedBy(proxyType)); } 

完整的组件注册是

 Container = new WindsorContainer(); Container.Kernel.Resolver.AddSubResolver(new CollectionResolver(Container.Kernel)); // Interceptor Container.Register(Component.For().ImplementedBy().LifestyleTransient()); // Component registrations RegisterComponent(); 

当然,您需要拦截的所有方法都应该是virtual因为使用了基于inheritance的代理。

但是,此解决方案的缺点是在创建代理对象时无法使用构造函数注入。 请注意,您只使用new运算符创建“虚拟”代理对象以获取代理类型。 因此,只有在构造虚拟代理时才能使用构造函数注入,但是当您通过容器解析服务时,注入可以正常工作。 所以这个缺点对于构造逻辑比仅依赖分配更复杂的组件至关重要。 如果只需要依赖项分配,则可以在创建虚拟代理之前尝试手动解析容器中的所有依赖项

 private object[] ResolveConstructorParameters() { return typeof(TType).GetConstructors() .Single(c => c.IsPublic) .GetParameters() .Select(p => _container.Resolve(p.ParameterType)) .ToArray(); } 

然后RegisterComponent将成为

 private void RegisterComponent() where TInterface : class where TImplementation : class, TInterface { var constructorParameters = ResolveConstructorParameters(); var proxyType = new ProxyGenerator().CreateClassProxy(typeof(TImplementation), constructorParameters).GetType(); _container.Register(Component.For().ImplementedBy(proxyType)); } 

您也可以使用null填充参数。

@NikolayKondratyev我已经调查了https://github.com/castleproject/Windsor/blob/master/src/Castle.Windsor/Windsor/Proxy/DefaultProxyFactory.cs#L110并且我已经轻松完成了注册: container.Register(Classes.FromThisAssembly().BasedOn(typeof(IRepositoryBase<,>)) .WithServiceAllInterfaces().WithServiceSelf() .LifestyleTransient());

注意。通过.WithServiceSelf()调用,这实际上会切换基于类的代理