Setter Injection in StructureMap 2.5

I know this isn’t the most exciting post I’ve ever written, but I’m blogging the new StructureMap 2.5 documentation as I create it.  I’ve done quite a bit of work in StructureMap 2.5 to extend the support for Setter Injection and it’s worthy of some attention for new and old StructureMap users.  *I* still think that Setter Injection is sub-optimal, but there are times when it’s necessary.  I’ll make a separate post later on how some of the newer setter injection support can be used to create an equivalent to Windsor’s logging facility.

 

Setter Injection

StructureMap supports two forms of Dependency Injection:

  1. Constructor Injection — "Pushing" dependencies into a concrete class through constructor arguments.
  2. Setter Injection — "Pushing" dependencies into a concrete class through public properties.  The "Setter" nomenclature is taken from Java where properties are getSomething() and setSomething(value).

You can certainly mix and match Setter Injection with Constructor Injection on the same classes, but Constructor Injection will always be used (except for empty constructors) and Setter Injection has to be explicitly configured.  See Martin Fowler’s discussion on Constructor versus Setter Injection for more information.  My feeling has always been that Constructor Injection is preferrable from a design perspective.  When you exclusively use Constructor Injection, the code is somewhat more self-documenting because the constructor arguments will clearly delineate the dependencies of a concrete class.  It’s also important to think about the constructor method of a class being a contract.  If you satisfy all of the arguments of the constructor method, the class should be ready to function.  Relying on Setter Injection can make a class harder to use because it isn’t always obvious which setters need to be created externally to use the class.  Of course, not using any form of Dependency Injection can be the worst answer because then you have no idea what it really takes to bootstrap the service.

Despite my personal distaste for Setter Injection, I gave into user demand and greatly increased StructureMap’s support for Setter Injection — and promptly found that support to be more useful than I thought it would be.

 

Using Setter Injection

Setter injection is a pattern of "injecting" dependencies via public properties.  Setter Injection with StructureMap is somewhat a second class citizen, but this is partially by design.  My strong recommendation is to use constructor injection for all code that you control, and save setter injection strictly for classes from external libraries where you do not have any control.  As a summary, these are the Setter Injection features that are described in detail below:

  • By default, all public "Setters" are optional, meaning that these setters will only be set if they are explicitly configured for a specific Instance
  • StructureMap can be directed to "auto wire" a property for a given Instance
  • Setters can be made mandatory by decorating the property with the [SetterProperty] attribute
  • Any type that StructureMap can use in constructor arguments can be used for setter properties
  • StructureMap can be directed to automatically inject the default value for any property of a given type.  This was added primarily for "optional" dependencies like logging.
  • The StructureMap diagnostic tools will check for missing Setter values

 

Configuring Primitive Setter Properties

Ok, now that you’ve read that I don’t believe that setter injection is a good idea, but you’re bound and determined to use it anyway, let’s talk about how to do it with StructureMap.  Let’s say we have this class with a string property called "Name":

    public class OptionalSetterTarget

    {

        public string Name { get; set;; }

    }

I can specify the value of the "Name" property in the configuration API like this:

        [Test]/p>

        public void optional_setter_injection_with_string()

        {

            var container = new Container(r =>

            {

                // The "Name" property is not configured for this instance

                r.InstanceOf<OptionalSetterTarget>().Is.OfConcreteType<OptionalSetterTarget>().WithName("NoName");

 

                // The "Name" property is configured for this instance

                r.ForConcreteType<OptionalSetterTarget>().Configure

                    .WithProperty("Name").EqualTo("Jeremy");

            });

 

            container.GetInstance<OptionalSetterTarget>().Name.ShouldEqual("Jeremy");

            container.GetInstance<OptionalSetterTarget>("NoName").Name.ShouldBeNull();

&        }

In the case above I specified the value for the "Name" setter directly by embedding the property value directly with the WithProperty("Name").EqualTo("Jeremy").  You could also retrieve the value for the property from the AppSettings portion of a .Net application config file like this with the WithProperty("Name").EqualToAppSetting("name") syntax.

            var container = new Container(r =>

            {

                r.ForConcreteType<OptionalSetterTarget>().Configure

                    .WithProperty("Name").EqualToAppSetting("name");

            });

In both of the cases above the property name is designated by a string.  Using strings to designate property names is always going to be somewhat problematic, so there’s a new option in 2.5 to specify property values with a Lambda expression (inspired by this post from Udi Dahan) using an Action<T>.

                r.ForConcreteType<OptionalSetterTarget>().Configure

                    .SetProperty(x => x.Name = "Jeremy");

The value of the Lamdba expression mechanism is that it makes the configuration static-typed with all of the advantages that static typing brings.  This action is executed on the object after creation.  Technically, this mechanism can be used to do anything to the new object before StructureMap returns the new object to the code that requested it.  There is no limitation to the number of Action<T> handlers you can use.

 

Configuring Setter Dependencies

Let’s say you have a class that has a public property for a singular dependency and another public property for an array of dependencies.

    public class ClassWithDependency

    {

        public Rule Rule { get; set; }

        public Rule[] Rules { get; set; }

    }

I can explicitly configure what gets injected into the "Rule" property for a specific Instance of ClassWithDependency like this with the .SetterDependency<T>() method that will look for the first public setter of type T:

                r.ForConcreteType<ClassWithDependency>().Configure

                    .SetterDependency<Rule>().Is(new ColorRule("Red"));

or for cases where a class may have multiple public setters of the same type, you can specify the exact property with an Expression (.SetterDependency<T>( expression ) ):

            var container = new Container(r =>

            {

                r.ForConcreteType<ClassWithDependency>().Configure

                    .SetterDependency<Rule>(x => x.Rule).Is(new ColorRule("Red"));

            });

 

"Auto Filling" a Setter Dependency

Sometimes all you want to do is to simply say "fill in this property for me."  That’s what the code below does for the "Rule" property with the .SetterDependency<Rule>().IsTheDefault() syntax:

            var container = new Container(r =>

            {

                r.ForConcreteType<ClassWithDependency>().Configure

                    .SetterDependency<Rule>().IsTheDefault();

 

                r.ForRequestedType<Rule>().TheDefault.Is.Object(new ColorRule("Green"));

            });

   

For certain dependency types you might want StructureMap to automatically fill any public property of that type.  The first usage that comes to mind is logging.  Let’s say that we have an interface for our logging support called ILogger.  We can specify that any concrete class that has a public property for the ILogger type will be filled in construction with code like this (FillAllPropertiesOfType<ILogger>()):

            var container = new Container(r =>

            {

                r.FillAllPropertiesOfType<ILogger>().TheDefault.Is

                    .ConstructedBy(context => new Logger(context.ParentType));

            });

Now, if I have some classes like:

    public class ClassWithLogger

    {

        public ILogger Logger { get; set; }

    }

 

    public class ClassWithLogger2

    {

        public ILogger Logger { get; set; }

    }

Now, when StructureMap builds new instances of these classes above the Logger properties will be filled automatically without any explicit configuration for either type.  Here’s a sample from the unit tests that constructs objects of both ClassWithLogger and ClassWithLogger2 and verifies that the "Logger" property was filled for both types without any further configuration.

 

            container.GetInstance<ClassWithLogger>().Logger.ShouldBeOfType<Logger>();

            container.GetInstance<ClassWithLogger2>().Logger.ShouldBeOfType<Logger>();

 

 

 

Defining Setter Properties with Attributes

Just use the [StructureMap.Attributes.SetterProperty] to denote properties that need to be filled by StructureMap.  Marking a property with the [SetterProperty] makes the setter mandatory.  StructureMap will throw an exception if the "ShouldCache" property isn’t specified for the concrete type shown below.  If the "Provider" property isn’t explicitly configured, StructureMap will use the default instance of IDataProvider for the "Provider" property (or throw an exception if StructureMap doesn’t know how to build the type IDataProvider).

    public class Repository

    {

        private IDataProvider _provider;

 

        // Adding the SetterProperty to a setter directs

        // StructureMap to use this property when

        // constructing a Repository instance

        [SetterProperty]/p>

        public IDataProvider Provider

        {

            set

            {

                _provider = value;

            }

        }

 

        [SetterProperty]

        public bool ShouldCache { get; set; }

    }


 

Defining Setter Properties in Xml

Setter properties can be defined in the Xml configuration by explicitly directing StructureMap to use setter properties while building a concrete type.  In the Xml, Setter configuration is done with the exact syntax as constructor arguments.  For example, the "Name" property of the OptionalSetterTarget class shown in previous sections can be set just like a constructor argument in an Xml node:

  <StructureMap MementoStyle="Attribute"

    <DefaultInstance

        PluginType="StructureMap.Testing.Pipeline.OptionalSetterTarget, StructureMap.Testing"

        PluggedType="StructureMap.Testing.Pipeline.OptionalSetterTarget, StructureMap.Testing"

        Name="Jeremy" />

  </StructureMap>


 

Setter properties can also be designated as mandatory setters with the <Setter> node in the Xml configuration.  From the unit tests, I have a class called OtherGridColumn that exposes several properties:

    public class OtherGridColumn : IGridColumn

    {

        public IWidget Widget { get; set; }

 

        public string ReadOnly

        {

            get { return "whatever"; }

        }

 

        public FontStyleEnum FontStyle { get; set; }

        public string ColumnName { get; set; }

        public Rule[] Rules { get; set; }

        public bool WrapLines { get; set; }

        public bool Displayed { get; set; }

        public int Size { get; set; }

    }

 


I can direct StructureMap to make the properties on the OtherGridColumn class mandatory in a <Plugin> node for OtherGridColumn.  This probably isn’t necessary with the new optional setter injection capabilities, but it is still valid and the equivalent of using the [SetterProperty] attribute.

  <PluginFamily/span> Type="StructureMap.Testing.Widget5.IGridColumn" Assembly="StructureMap.Testing.Widget5" DefaultKey="">

    <Plugin Assembly="StructureMap.Testing.Widget5" Type="StructureMap.Testing.Widget5.OtherGridColumn" ConcreteKey="Other">

      <Setter Name="ColumnName" />

      <Setter Name="FontStyle" />

      <Setter Name="Rules" />

      <Setter Name="Widget" />

      <Setter Name="WrapLines" />

    </Plugin>

  </PluginFamily&>

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.