2

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!

gradyal
  • 21
  • 1
  • Have a look at the documentation. https://github.com/castleproject/Windsor/blob/master/docs/how-properties-are-injected.md You can subclass `PropertiesDependenciesModelInspector` which should allow you to remove a lot of the boilerplate – Krzysztof Kozmic Aug 17 '18 at 07:05
  • @KrzysztofKozmic That's essentially what I've done with my workaround I mentioned above although I inherited directly from IContributeComponentModelConstruction. The only way that this (or the subclass of PropertiesDependenciesModelInspector) works is if I remove the implementation of PropertiesDependenciesModelInspector from the ComponentModelBuilder and add my own. But my implementation ends up being very similar to the original apart from the check for my own attribute. – gradyal Aug 18 '18 at 14:51
  • @KrzysztofKozmic So is the example in this documentation here: https://github.com/castleproject/Windsor/blob/aa9b8b353ee2e533d586495eec254e216f800c09/docs/componentmodel-construction-contributors.md no longer valid? That's a much simpler approach. – gradyal Aug 18 '18 at 14:52
  • The documentation should be valid. The first example was just more closely related – Krzysztof Kozmic Aug 20 '18 at 15:03
  • @KrzysztofKozmic Got it. So if the link that I provided is valid, any ideas on how to make that approach work? I'm just trying to figure out what I'm missing. – gradyal Aug 20 '18 at 15:21

0 Answers0