Although I prefer constructor injection, I want developers on my team to be able to use property injection as long as they explicitly mark the property as injectable with an attribute. According to CastleWindsor documentation here, this should be possible by creating a contributor and then calling AddContributor with it through the Kernel. I cannot seem to get this to work. All public properties (even those without the attribute) are injected.
When I set a breakpoint in my contributor ProcessModel method, it sets all properties with the attribute to mandatory (IsOptional = false) and skips over any properties that do not have the attribute. But despite this, the properties without the attribute still get injected. What am I doing wrong?
Below is my code:
Contributor
public class PropertyInjectionContributor : IContributeComponentModelConstruction
{
public void ProcessModel(IKernel kernel, ComponentModel model)
{
model.Properties
.Where(p => p.Property.IsDefined(typeof(InjectedAttribute)))
.All(p => p.Dependency.IsOptional = false);
}
}
Attribute
[AttributeUsage(AttributeTargets.Property)]
public class InjectedAttribute : Attribute { }
Add contributor to Kernel.ComponentModelBuilder and register components
public class Program
{
public static void Main(string[] args)
{
var container = new WindsorContainer();
container.Kernel.ComponentModelBuilder.AddContributor(new PropertyInjectionContributor());
container.Register(Component.For<IClass1>()
.ImplementedBy<Class1>()
.LifestyleTransient());
container.Register(Component.For<IClass2>()
.ImplementedBy<Class2>()
.LifestyleTransient());
var class1 = container.Resolve<IClass1>();
class1.DoSomething();
}
}
Class1
public class Class1 : IClass1
{
//[Injected]
public IClass2 Class2 { get; set; }
public void DoSomething()
{
Class2.DoSomething();
}
}
The Class2 property within Class1 is injected even though it is not decorated with the Injected attribute.
My current workaround for this is to remove CastleWindsor's PropertiesDependenciesModelInspector and replace it with an implementation that forces IsOptional to be false. It works but it repeats a lot of CW's code. I'd prefer to use the simple approach above if I can only get it to work!
You're only setting IsOptional if the property has the attribute. You're not doing anything for properties without the attribute. For all those properties you don't want injected, you'd need to mark them as not injectable. There is an attribute that already does this: [DoNotWire].