以下代码按Castle.Windsor 2.5.3格式传递,但在升级到3.1.0后失败
异常是InvalidProxyConstructorArgumentsException,它指出“无法实例化类的代理:Test。无法找到无参数的构造函数。”
static void Main(string[] args)
{
var container = new WindsorContainer();
container.Register(Component.For<Interceptor>(),
Component.For<Test>().UsingFactoryMethod(() => new Test(""))
.Interceptors<Interceptor>());
var test = container.Resolve<Test>(); //THROWS IN 3.1.0
}
}
public class Test
{
public readonly string S;
public Test(string s)
{
S = s;
}
}
public class Interceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
}
}
在我的实际代码中,Test是一个使用工厂方法构建并注入存储库的MongoDatabase。
在我的实际代码中,我还使用了一个AbstractFacility的继承者来注册拦截器。这样我就不必为每个组件注册拦截器。两种形式的拦截器使用似乎在后续解决方案中以相同的方式工作/失败(在2.5.3 / 3.1.0中)。这里提供的是该设施的缩短版本:
public class Facility : AbstractFacility
{
protected override void Init() { Kernel.ComponentRegistered += KernelComponentRegistered; }
static void KernelComponentRegistered(string key, IHandler handler)
{
if (typeof(IInterceptor).IsAssignableFrom(handler.ComponentModel.Implementation)) return;
handler.ComponentModel.Interceptors.AddIfNotInCollection(InterceptorReference.ForKey("SomeInterceptor"));
}
}
我查看了Castle.Windsor源代码和抛出代码,期望在给定的类周围包装代理,这就是为什么它正在寻找无参数构造函数。但是在2.5.3中,我认为代理生成代码永远不会被执行,容器会在我的脑海中解析为非代理版本的Test / MongoDatabase
我猜两个问题: 1)有什么变化? 2)如何在不为工厂方法解析的对象生成代理的情况下保持拦截器注册?或者我想如何使用组件的工厂方法生成代理...
答案 0 :(得分:2)
在2.5.3中,温莎似乎默默无法应用拦截器。在3.1.0中,当Windsor无法将拦截器应用于您已注册的类型时,会引发异常。 Windsor使用其动态代理库通过生成您要求的实例的代理来支持拦截器(AOP)。因此,两个版本中的问题是,您提供的类不能转换为动态代理,因为它没有no-arg构造函数。我认为3.1.0中的行为更正确,因为如果你期望应用拦截器,那么找出问题是很困难的。
如果要保持2.5.3静默失败的行为,只需添加一个检查,看看在您的设施中注册拦截器之前是否可以代理该类型。这样做可能会更好,但这就是我想出的:
try
{
ProxyGenerator generator = new ProxyGenerator();
generator.CreateClassProxy(handler.ComponentModel.Implementation);
handler.ComponentModel.Interceptors.AddIfNotInCollection(InterceptorReference.ForType<MyInterceptor>());
}
catch {}
这在许多方面都是可怕的代码,但它会重现您已经习惯的行为。请注意,当你想要拦截器并且正在努力弄清楚为什么没有被拦截时,它不会让你不顺利。
答案 1 :(得分:0)
public class Facility : AbstractFacility
{
protected override void Init() { Kernel.ComponentRegistered += KernelComponentRegistered; }
static readonly List<Type> TypesNotToIntercept = new List<Type>
{
typeof(IInterceptor), //Don't intercept Interceptors
typeof(MulticastDelegate), //Func<> and the like
typeof(LateBoundComponent), //Resolved with a factory, such as MongoDatabase
};
static void KernelComponentRegistered(string key, IHandler handler)
{
if (TypesNotToIntercept.Any(type => type.IsAssignableFrom(implementation));
return;
handler.ComponentModel.Interceptors.AddIfNotInCollection(InterceptorReference.ForKey("SomeInterceptor"));
}
}