Building arrays in StructureMap 2.5

Although it was possible in previous versions of StructureMap, the new fluent interface for StructureMap configuration in version 2.5 allows easy configuration of array type constructor parameters.  For example, consider a simple order processor pipeline:

public class OrderPipeline
{
    private readonly IOrderPipelineStep[] _steps;

    public OrderPipeline(IOrderPipelineStep[] steps)
    {
        _steps = steps;
    }

    public IOrderPipelineStep[] Steps
    {
        get { return _steps; }
    }

    public OrderPipelineResponse Execute(OrderPipelineRequest request)
    {
        OrderPipelineResponse response = null;
        foreach (var step in _steps)
        {
            response = step.ExecuteStep(request);
            if (!response.IsSuccessful)
                return response;
        }
        return response;
    }
}

This pipeline takes an array of pipeline steps.  Given a pipeline request, which may contain information necessary for the steps, it executes each of the steps in order.  If any of the responses is not successful, the pipeline stops executing and returns the current response.

No where in this pipeline do we see which steps should be created.  Some steps may require service location from StructureMap, while others may not have any dependencies.  In any case, we want the construction of the pipeline steps for the pipeline to be external from the pipeline, as we can see it’s only concerned with executing steps.

But someone has to be concerned with which steps can be executed.  For many of our dependencies, the DefaultConventionScanner is all we need to construct our dependencies.  With an array parameter, there is no way StructureMap could automatically figure out which dependencies to create, and which order.  Instead, we can create a custom Registry to configure our dependency:

public class PipelineRegistry : Registry
{
    protected override void configure()
    {
        ForRequestedType<OrderPipeline>()
            .TheDefault.Is.OfConcreteType<OrderPipeline>()
            .TheArrayOf<IOrderPipelineStep>()
            .Contains(x =>
                          {
                              x.OfConcreteType<ValidationStep>();
                              x.OfConcreteType<SynchronizationStep>();
                              x.OfConcreteType<RoutingStep>();
                              x.OfConcreteType<PersistenceStep>();
                          });
    }
}

In this Registry, I tell StructureMap first what the requested and default concrete types are.  Next, I tell StructureMap that the array of IOrderPipelineStep contains a set of concrete types.  The Contains method takes a delegate, so I can use a lambda to configure all of the individual concrete types.  Each step is created in the order I specify in the lambda block.  Here’s the passing test:

[Test]
public void Should_construct_the_pipeline_steps_correctly()
{
    StructureMapConfiguration
        .ScanAssemblies()
        .IncludeTheCallingAssembly()
        .With<DefaultConventionScanner>();

    var pipeline = ObjectFactory.GetInstance<OrderPipeline>();

    pipeline.Steps.Length.ShouldEqual(4);
    pipeline.Steps[0].ShouldBeOfType(typeof (ValidationStep));
    pipeline.Steps[1].ShouldBeOfType(typeof (SynchronizationStep));
    pipeline.Steps[2].ShouldBeOfType(typeof (RoutingStep));
    pipeline.Steps[3].ShouldBeOfType(typeof (PersistenceStep));
}

Notice that I did not need to specify the individual Registry.  StructureMap scans the given assemblies for Registries, and automatically adds them to the configuration.  Next, I ask StructureMap for an instance of the OrderPipeline.  Again, nowhere do we see any code for constructing the correct list of IOrderPipelineSteps, this is encapsulated in our Registry.  Finally, the rest of the test asserts that both the correct steps were created, and in the right order.

With the new fluent interface in StructureMap 2.5, I get a nice declarative interface to configure all of the special dependencies.  Although the DefaultConventionScanner picks up almost all of my dependencies, in some special cases I still need to configure them.  Array dependencies are created simply enough just with a lambda specifying the correct steps.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in StructureMap. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://realfiction.net Frank Quednau

    Hello sir (!),
    methinks I need just that, and yet, I can only get hold of a 2.4 version. The lovely definition of an array dependency is sadly absent from my build. You mention that such a configuration was previously possible, but there seems to be an inverse law of DI framework quality with regard to its state of documentation ;)
    btw, who would know what the default is for the defaultconventionscanner?
    kind regards,
    Frank

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Frank

    I’d have to look back…you can do quite a bit of things in a custom Registry. There should be something there to set up constructor arguments. You’d probably just have to do a bit more work.

    As for the DefaultConventionScanner, I’ll just post its rules soon.