The following code passes as-is with Castle.Windsor 2.5.3 but fails after upgrading to 3.1.0
The exception is an InvalidProxyConstructorArgumentsException and it states "Can not instantiate proxy of class: Test. Could not find a parameterless constructor."
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();
}
}
In my real code Test is a MongoDatabase that is being constructed using a factory method and injected into a Repository.
In my real code I'm also using an inheritor to an AbstractFacility to register the interceptor. This way I don't have to register the interceptor for each component. Both forms of interceptor usage seem to work/fail (in 2.5.3/3.1.0) the same way on later resolution. For reference here is a shortened version of the facility:
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"));
}
}
I looked at the Castle.Windsor source code and the throwing code is expecting to wrap a proxy around the class it is given which is why it's looking for a parameterless constructor. However in 2.5.3 I think the proxy generation code never got executed and the container resolves (correctly in my mind) to a non-proxy version of Test/MongoDatabase
So two questions I guess: 1) What's changed? 2) How do I keep my interceptor registration without generating a proxy for the object resolved by the factory method? Or I guess how does a proxy get generated using a factory method for the component...
In 2.5.3, Windsor appears to be silently failing to apply the interceptor. In 3.1.0, Windsor throws an exception when it can't apply the interceptor to the type that you've registered. Windsor uses their Dynamic Proxy library to support interceptors (AOP) by generating proxies of the instances that you ask for. So the problem in both versions is that the class you're giving it cannot be turned into a dynamic proxy because it does not have a no-arg constructor. I would consider the behavior in 3.1.0 to be more correct since if you were expecting the interceptor to be applied, it would be a lot more difficult to figure out what the problem is.
If you want to maintain the behavior from 2.5.3 where it fails silently, just add a check to see if the type can be proxied before you register the interceptor in your facility. There's probably a better of doing it, but here's what I came up with:
This is terrible code in so many ways, but it will recreate the behavior that you're used to. Just be careful that it doesn't bite you down the road when there's a different class that you actually want the interceptor on and are struggling to figure out why it's not being called.