Fork me on GitHub

Auto Wiring Edit on GitHub


The best way to use an IoC container is to allow "Auto Wiring" to do most of the work for you. IoC Containers like StructureMap are an infrastructure concern, and as such, should be isolated from as much of your code as possible. Before examining Auto Wiring in depth, let's look at a common anti pattern of IoC usage:


// This is the wrong way to use an IoC container.  Do NOT invoke the container from
// the constructor function.  This tightly couples the ShippingScreenPresenter to
// the IoC container in a harmful way.  This class cannot be used in either
// production or testing without a valid IoC configuration.  Plus, you're writing more
// code
public ShippingScreenPresenter(IContainer container)
{
    // It's even worse if you use a static facade to retrieve
    // a service locator!
    _service = container.GetInstance<IShippingService>();
    _repository = container.GetInstance<IRepository>();
}

Instead of binding ShippingScreenPresenter so tightly to StructureMap and having to explicitly fetch its dependencies, let's switch it to using StructureMap a little more idiomatically and just exposing a constructor function with the necessary dependencies as arguments:


// This is the way to write a Constructor Function with an IoC tool
// Let the IoC container "inject" services from outside, and keep
// ShippingScreenPresenter ignorant of the IoC infrastructure
public ShippingScreenPresenter(IShippingService service, IRepository repository)
{
    _service = service;
    _repository = repository;
}

As long as a StructureMap Container knows how to resolve the IRepository and IShippingService interfaces, StructureMap can build ShippingScreenPresenter by using "auto-wiring." All this means is that instead of forcing you to explicitly configure all the dependencies for ShippingScreenPresenter, StructureMap can infer from the public constructor function and public property setters what dependencies ShippingScreenPresenter needs and uses the defaults of both to build it out.

Looking at the build plan for ShippingScreenPresenter:


public void ShowBuildPlan()
{
    var container = new Container(_ =>
    {
        _.For<IShippingService>().Use<InternalShippingService>();
        _.For<IRepository>().Use<SimpleRepository>();
    });

    // Just proving that we can build ShippingScreenPresenter;)
    container.GetInstance<ShippingScreenPresenter>().ShouldNotBeNull();

    var buildPlan = container.Model.For<ShippingScreenPresenter>().Default.DescribeBuildPlan(1);

    Debug.WriteLine(buildPlan);
}

give us:

PluginType: StructureMap.Testing.DocumentationExamples.ShippingScreenPresenter
Lifecycle: Transient
new ShippingScreenPresenter(IShippingService, IRepository)
  ┣ IShippingService = **Default**
  ┃                     | PluginType: StructureMap.Testing.DocumentationExamples.IShippingService
  ┃                     | Lifecycle: Transient
  ┃                     | new InternalShippingService()
  ┃                    
  ┗ IRepository = **Default**
               | PluginType: StructureMap.Testing.DocumentationExamples.IRepository
               | Lifecycle: Transient
               | new SimpleRepository()
              

See Working with Primitive Types for more information on how StructureMap deals with primitive types like numbers, strings, enums, and dates in auto-wiring.