Click here to Skip to main content
15,887,135 members
Articles / Programming Languages / C#
Tip/Trick

Forcing Property Injection with Castle Windsor

Rate me:
Please Sign up or sign in to vote.
4.89/5 (4 votes)
8 Oct 2015CPOL4 min read 16.1K   3   2
How to override Castle Windsor's default behavior and make properties into required dependencies.

Introduction

This tip illustrates how Castle Windsor's default behavior can be modified such that properties can be marked as being required.

Background

In Castle Windsor, there are two basic ways in which the container system can inject dependencies. The first (and arguably most common) is through constructor injection, whereby the container automatically calls your constructor with the correct dependencies. The second way is through property injection. With property injection, the container will automatically inject any dependencies that it can satisfy prior to calling the object's constructor.

When using constructor injection, the developer is required to spell out all of the dependencies required by an object up front. This can make things such as writing tests or even simply reasoning with the code easier since there's no ambiguity between what's required and what is optional. The downside to this approach however is that not all of these "required" dependencies really are required (e.g. certain methods may only need certain dependencies). Additionally, constructor injection forces any child-classes to have explicit knowledge of the base class's dependencies since the sub-class's constructor must in turn call the base class's constructor. Finally, there is a certain amount of boilerplate code that must be written to accomplish this. First a read-only field must be created for the dependency, then a constructor that takes the dependency, and finally an assignment statement setting the field.

On the other side of the coin, we have property injection. With property injection, we simply create a public property with a getter/setter and the container system does the rest. While this negates most of the overhead that comes with constructor injection, it comes with one caveat. By default, if the container system can't satisfy a dependency then it will simply skip it. This is in contrast with constructor injection whereby the container system would throw an exception if any of the required dependencies could not be resolved. So, is there a way to override this behavior such that we can take advantage of the succinctness of property injection without sacrificing the safeguards afforded by constructor injection? The answer fortunately is yes!

Using the Code

I'm a huge fan of Castle Windsor. One of the things I love about it is how simple it is to override just about every way the system works. While "it just works" 99% of the time, there's usually an interface and/or callback for those occasional instances where you need that little extra control. In this example we're going to take a closer look at the IContributeComponentModelConstruction interface.

Castle already has excellent documentation on how this interface works so I'm not going to plagiarize them. Essentially what this interface allows us to do is "tweak" components before they're officially "baked" into the container. Castle's own documentation already shows a simple example of using this interface in order to make a specific property mandatory. What we're going to do here is create a more generalized solution so that any property can be marked as being required.

The first thing we need to do in order to accomplish this is to annotate our properties so that they can easily be identified as being required. This can be done with a simple attribute.

C#
[AttributeUsage(AttributeTargets.Property, AllowMultiple=false)]
public class MandatoryAttribute : Attribute { } 

The second step is to decorate our properties with the attribute to designate them as being required. This is as simple as:

C#
public class MyClass
{
    [Mandatory] public IMyDependency SomeDependency { get; set; }
}

The third step is to create the component model construction contributor itself. The idea here is to use reflection to look for the presence of our Mandatory attribute in order to allow that property to "opt-in" to our updated behavior. That implementation looks like this:

C#
public class MandatoryPropertyComponentModelHelper : IContributeComponentModelConstruction
{
    public void ProcessModel(IKernel kernel, ComponentModel model)
    {
        foreach(var property in model.Properties)
        {
            if(property.Property.GetCustomAttributes(inherit: true).Any(x => x is MandatoryAttribute))
            {
                property.Dependency.IsOptional = false;
            }
        }
    }
}

The last step is tell Castle to use our contributor. The easiest way to do this is to simply call the AddContributor() method of the kernel's ComponentModelBuilder property.

Final Thoughts

One thing I like to remind developers whenever I show them a tool or "trick" is that they should never view it as a panacea. This technique can help eliminate boilerplate code and hide dependencies from sub-classes, but it can also make it harder to reason about what a class needs since that information is no longer encoded in the constructor. Good judgement is key.

Also, this tip focuses solely on Castle Windsor. Not to besmirch other excellent DI systems (e.g. Autofac, StructureMap, Ninject, Unity, etc...), but I'm simply not fluent enough in them to offer code analogs. If anyone wants to translate the code examples to specific language for another container I'll gladly update this.

Finally, one last thing to keep in mind is that when using property injection that castle will inject the properties after the constructor has been called. Keep this in mind if you need to perform initialization that requires these dependencies.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) McKesson
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
BugIt does not work!! Pin
Veronica S. Zotali21-Jul-17 3:01
Veronica S. Zotali21-Jul-17 3:01 
GeneralMy vote of 5 Pin
Farhad Reza15-Oct-15 20:58
Farhad Reza15-Oct-15 20:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.