Reputation:
Can anyone explain why this doesn't work? If you remove the interceptor from IFoo's registration and resolve a Bar, you get a Foo (MyFoo isn't null). But with the interceptor, the Foo doesn't resolve anymore.
Why? How can I tell why it won't resolve via logging or tracing?
Versions:
C# 5
using Castle.DynamicProxy;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using System;
namespace Sandbox
{
public interface IFooInterceptor : IInterceptor { }
public interface IFoo
{
void Print();
}
public interface IBar
{
IFoo MyFoo { get; set; }
}
public class Foo : IFoo
{
public void Print()
{
Console.WriteLine("Print");
}
}
public class FooInterceptor : IFooInterceptor, IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("Awesome");
invocation.Proceed();
}
}
public class Bar : IBar
{
public virtual IFoo MyFoo { get; set; }
}
class Program
{
static void Main(string[] args)
{
IWindsorContainer container = new WindsorContainer()
.Register(
Component.For<IBar>().ImplementedBy<Bar>().LifestyleTransient(),
Component.For<IFoo>().ImplementedBy<Foo>().LifestyleTransient().Interceptors<IFooInterceptor>(),
Component.For<IFooInterceptor>().ImplementedBy<FooInterceptor>().LifestyleTransient()
);
var bar = container.Resolve<IBar>();
var foo = container.Resolve<IFoo>(); // this isn't null
bar.MyFoo.Print(); // exception: bar.MyFoo is null
Console.WriteLine("Done");
Console.ReadLine();
}
}
}
Edit: I just found (mostly by accident) that changing the interceptor config from an interface to a concrete class works. However, I'm registering the interceptor and its interface, so the original question is amended slightly: why does the interface specification fail (silently, no less)?
Upvotes: 5
Views: 801
Reputation: 139758
Castle handles properties as optional dependencies but it should inject them by default. But it seems that combined with the Interceptors these optional dependencies are not resolved correctly.
What you can do you is to make your dependencies required by changing Bar to use constructor injection:
public class Bar : IBar
{
public Bar(IFoo foo)
{
MyFoo = foo;
}
public virtual IFoo MyFoo { get; private set; }
}
Or register Bar with the Properties
explicitly marked required:
Component.For<IBar>().ImplementedBy<Bar>().LifestyleTransient()
.Properties(PropertyFilter.RequireAll)
Note: in production you should use the PropertiesRequired
method instead of the Properties
because it is obsolete now.
I've also found this github issue which also seemed relevant: Bug - optional dependencies not provided
Upvotes: 2