Fork me on GitHub

Passing Arguments at Runtime Edit on GitHub


Most of the time you will be using StructureMap to build objects based on pre-canned configuration established upfront, but StructureMap also has the capability to supply dependencies by type or named parameters (if you know the name of constructor arguments or setter property names) to the Container at runtime using the IContainer.With() methods.

Why would you use this? Here are a few examples from my own usage over the years:

  1. In adhoc code, retrieve some service but override a connectionString constructor argument to connect to a different database
  2. If you were to use StructureMap as a configuration intermediary, it becomes common to use this mechanism to swap out configuration on the fly
  3. Inject an Entity object into a service (uncommon now, but I did this on several systems years ago)
  4. Inject something contextual that can only be built at runtime like an ASP.Net HttpContext into a pre-configured object graph

Now, for some samples. Let's say that we have some classes like so:


public class ColorWidget : IWidget
{
    public string Color { get; set; }

    public ColorWidget(string color)
    {
        Color = color;
    }
}

public class GuyWithWidgetAndService
{
    public IWidget Widget { get; set; }
    public IService Service { get; set; }

    public GuyWithWidgetAndService(IWidget widget, IService service)
    {
        Widget = widget;
        Service = service;
    }
}


and unless stated otherwise in a sample, a Container configured like so:


var container = new Container(x =>
{
    x.For<IWidget>().Use<BWidget>();
    x.For<IService>().Use<AService>();
});

Passing Named Arguments

The original usage of explicit arguments was to replace primitive arguments to constructor functions like this sample:


[Fact]
public void supply_named_arguments()
{
    var container = new Container(x => { x.For<IWidget>().Use<ColorWidget>().Ctor<string>().Is("Red"); });

    container.GetInstance<IWidget>()
        .ShouldBeOfType<ColorWidget>()
        .Color.ShouldBe("Red");

    container.With("color").EqualTo("Blue")
        .GetInstance<IWidget>()
        .ShouldBeOfType<ColorWidget>()
        .Color.ShouldBe("Blue");
}


The canonical usage is overriding file paths, database connection string, or urls.

Passing Arguments with a Fluent Interface

You can invoke the explicit argument passing as a fluent interface starting with IContainer.With() like the following sample:


var widget = new BWidget();
var service = new BService();

var guyWithWidgetAndService = container
    .With<IWidget>(widget)
    .With<IService>(service)
    .GetInstance<GuyWithWidgetAndService>();

guyWithWidgetAndService
    .Widget.ShouldBeTheSameAs(widget);

guyWithWidgetAndService
    .Service.ShouldBeTheSameAs(service);

Using a Nested Closure

If you dislike fluent interfaces or want to pass in a lot of dependencies, the nested closure syntax might be more usable:


var widget = new BWidget();
var service = new BService();

var guyWithWidgetAndService = container
    .With(x =>
    {
        x.With<IWidget>(widget);
        x.With<IService>(service);
    })
    .GetInstance<GuyWithWidgetAndService>();

guyWithWidgetAndService
    .Widget.ShouldBeTheSameAs(widget);

guyWithWidgetAndService
    .Service.ShouldBeTheSameAs(service);

Using the ExplicitArguments object

Finally, you can also pass an object of type ExplicitArguments directly to an overload of the IContainer.GetInstance() method:


var widget = new BWidget();
var service = new BService();

var args = new ExplicitArguments();
args.Set<IWidget>(widget);
args.Set<IService>(service);

var guyWithWidgetAndService = container
    .GetInstance<GuyWithWidgetAndService>(args);

guyWithWidgetAndService
    .Widget.ShouldBeTheSameAs(widget);

guyWithWidgetAndService
    .Service.ShouldBeTheSameAs(service);