The fact that the interceptor wasn't being assigned to Test in 2.5.3 is a bug/feature disguised as a bug. The 3.1.0 behaviour is more correct, and forces you to be explicit about what you want an interceptor on. Since my actual code involved a Facility, here is the solution that fixes the issue:
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; //This is so that interceptors don't intercept themselves
if (handler.ComponentModel.Services.FirstOrDefault() == typeof(Test)) return; //This is so that the interceptor does not intercept our Factory-initialized class
handler.ComponentModel.Interceptors.AddIfNotInCollection(InterceptorReference.ForKey("SomeInterceptor"));
}
}
On Friday, 28 September 2012 01:34:11 UTC-7, Nik Pinski wrote:
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...