Yoann. B
Yoann. B

Reputation: 11143

Array Constructor Dependency With StructureMap

I've some ITask concretes types defines in my TaskRegistry:

public class TaskResigstry : Registry
{
    public TaskResigstry()
    {
        ForRequestedType<IBootstrapperTask>().TheDefaultIsConcreteType<StartTasks>();

        ForRequestedType<ITask>().TheDefaultIsConcreteType<FirstTask>();
        ForRequestedType<ITask>().AddConcreteType<SecondTask>();
        ForRequestedType<ITask>().AddConcreteType<ThirdTask>();
    }
}

And my StartTasks

public class StartTasks : IBootstrapperTask
{
    public StartTasks(ITask[] tasks)
    {
        foreach(var task in tasks)
        {
            task.Run();
        }
    }
}

How can i inject the ITask[] constructor parameter using StructureMap ?

Thanks.

Upvotes: 3

Views: 1368

Answers (3)

NightOwl888
NightOwl888

Reputation: 56849

The accepted answer is good, but the syntax is out of date. Here is the new syntax to do the same:

this.For<IBootStrapperTask>().Use<StartTasks>()
    .EnumerableOf<ITask>().Contains(x =>
    {
        x.Type<Task1>();
        x.Type<Task2>();
        x.Type<Task3>();
    });

StructureMap is great, but I am often frustrated by the lack of examples that use the most up-to-date syntax.

Upvotes: 1

John Foster
John Foster

Reputation: 8745

If you want to inject an Array there's a method for that in the fluent interface...

ForRequestedType<IBootStrapperTask>().TheDefault.Is.OfConcreteType<StartTasks>()
     .TheArrayOf<ITask>().Contains(
            y => {
                y.OfConcreteType<Task1>();
                y.OfConcreteType<Task2>();
                y.OfConcreteType<Task3>();
            });

If you want to go down the route of an accepting an IEnumerable<T> in your constructor as far as I can see things start to become a little more complicated. You can specify and build the constructor argument like so:-

ForRequestedType<IBootStrapperTask>().TheDefault.Is.OfConcreteType<StartTasks>()
            .CtorDependency<IEnumerable<ITask>>().Is(i => {
                i.Is.ConstructedBy(c => {
                    return new List<ITask> { 
                           c.GetInstance<Task1>(), 
                           c.GetInstance<Task2>(), 
                           c.GetInstance<Task3>()
                    };
                });
            });

If you want all the registered types you could make a custom IBuildInterceptor that accesses all the registered types via the CreateInstanceArray method on the BuildSession but I get the feeling I might be going down the wrong road there.

I'd love to be corrected that this is a lot easier :).

Upvotes: 3

Joshua Flanagan
Joshua Flanagan

Reputation: 8557

You don't have to do anything more. Just ask for an instance of IBootstrapperTask, and all of the ITasks will automatically be injected.

var container = new Container(x => x.AddRegistry<TaskResigstry>());
var bootstrapper = container.GetInstance<IBootstrapperTask>();

Note: StructureMap will only recognize arrays for injecting multiple instances - do not change the constructor to take an IEnumerable or strongly typed collection.

As a shortcut, if you want to inject all instances of ITask in your assembly, without having to manually register all of them, you can change your registry to:

public class TaskResigstry : Registry
{
    public TaskResigstry()
    {
        ForRequestedType<IBootstrapperTask>().TheDefaultIsConcreteType<StartTasks>();

        Scan(x =>
        {
            x.TheCallingAssembly();
            x.AddAllTypesOf<ITask>();
        });
    }
}

Upvotes: 3

Related Questions