Fork me on GitHub

Registry DSL Edit on GitHub


Creating Registry classes is the recommended way of using the Registry DSL.

The Registry DSL is mostly a fluent interface with some nested closure usage. The intent of the Registry DSL is to make the configuration process as error free as possible by using "compiler safe" expressions and defensive programming to point out missing data.

The Registry Class

On all but the smallest systems, the main unit of configuration will probably be the Registry class. Typically, you would subclass the Registry class, then use the fluent interface methods exposed by the Registry class to create Container configuration. Here's a sample Registry class below used to configure an instance of an IWidget interface:


public class PurpleRegistry : Registry
{
    public PurpleRegistry()
    {
        For<IWidget>().Use<AWidget>();
    }
}

Including Registries

The next question is "how does my new Registry class get used?"

When you set up a Container, you need to simply direct the Container to use the configuration in that Registry class:


[Fact]
public void include_a_registry()
{
    var registry = new Registry();
    registry.IncludeRegistry<YellowBlueRegistry>();
    registry.IncludeRegistry<RedGreenRegistry>();
    registry.IncludeRegistry<PurpleRegistry>();
    // build a container
    var container = new Container(registry);
    // verify the default implementation and total registered implementations
    container.GetInstance<IWidget>().ShouldBeOfType<AWidget>();
    container.GetAllInstances<IWidget>().Count().ShouldBe(5);
}

Use versus Add

Registrations in the Registry DSL can be done with either Add() or Use() methods, but they have a different semantic meaning to StructureMap. Add() means add another Instance to this plugin type while Use() means this one is the default.

One of the things that is different about StructureMap is that if it has multiple registrations of any given plugin type, one of these registrations has to be explicitly marked as the default usage for that plugin type or StructureMap will blow up in the call to Container.GetInstance(). Other IoC tools will magically use the first registration or the last registration (and some even allow you to configure that behavior). We chose to make that determination be explicit.

As of StructureMap 3.0, the WhatDoIHave() output is part of any exception thrown by StructureMap when it cannot determine a default registration for a requested type if there is more than one registration for that type.

If there are multiple calls to Use() for the same plugin type, the last one wins. For more control over this behavior in modularity scenarios, see Fallback Services and Replace or Clear Out Previous Registrations.

For().Use()

To register the default Instance of a type, the syntax is one of the Registry.For().Use() overloads shown below:


public class SettingDefaults : Registry
{
    public SettingDefaults()
    {
        // If you know the plugin type and its a closed type
        // you can use this syntax
        For<IWidget>().Use<DefaultWidget>();

        // By Lambda
        For<IWidget>().Use(() => new DefaultWidget());

        // Pre-existing object
        For<IWidget>().Use(new AWidget());

        // This is rare now, but still valid
        For<IWidget>().Add<AWidget>().Named("A");
        For<IWidget>().Add<BWidget>().Named("B");
        For<IWidget>().Use("A"); // makes AWidget the default

        // Also rare, but you can supply an Instance object
        // yourself for special needs
        For<IWidget>().UseInstance(new MySpecialInstance());

        // If you're registering an open generic type
        // or you just have Type objects, use this syntax
        For(typeof (IService<>)).Use(typeof (Service<>));

        // This is occasionally useful for generic types
        For(typeof (IService<>)).Use(new MySpecialInstance());
    }
}

For().Add()

To register additional Instances for a plugin type, use one of the overloads of For().Add():


public class AdditionalRegistrations : Registry
{
    public AdditionalRegistrations()
    {
        // If you know the plugin type and its a closed type
        // you can use this syntax
        For<IWidget>().Add<DefaultWidget>();

        // By Lambda
        For<IWidget>().Add(() => new DefaultWidget());

        // Pre-existing object
        For<IWidget>().Add(new AWidget());

        // Also rare, but you can supply an Instance object
        // yourself for special needs
        For<IWidget>().AddInstance(new MySpecialInstance());

        // If you're registering an open generic type
        // or you just have Type objects, use this syntax
        For(typeof(IService<>)).Add(typeof(Service<>));

        // This is occasionally useful for generic types
        For(typeof(IService<>)).Add(new MySpecialInstance());
    }
}

Add Many Registrations with For().AddInstances()

If you need to add several Instances to a single plugin type, the AddInstances() syntax shown below may be quicker and easier to use:



// registry is a StructureMap Registry object
registry.For<IService>().AddInstances(x =>
{
    // Equivalent to For<IService>().Add<ColorService>().....
    x.Type<ColorService>().Named("Red").Ctor<string>("color").Is("Red");

    // Equivalent to For<IService>().Add(new ColorService("Yellow"))......
    x.Object(new ColorService("Yellow")).Named("Yellow");

    // Equivalent to For<IService>().Use(() => new ColorService("Purple"))....
    x.ConstructedBy(() => new ColorService("Purple")).Named("Purple");

    x.Type<ColorService>().Named("Decorated").Ctor<string>("color").Is("Orange");
});

Named Instances

When you have multiple implementations of an interface, it can often be useful to name instances. To retrieve a specific implementation:


[Fact]
public void SimpleCaseWithNamedInstance()
{
    container = new Container(x => { x.For<IWidget>().Add<AWidget>().Named("MyInstance"); });
    // retrieve an instance by name
    var widget = (AWidget)container.GetInstance<IWidget>("MyInstance");
    widget.ShouldNotBeNull();
}

You can also register named instances with the following shorthand:


[Fact]
public void A_concrete_type_is_available_by_name_when_it_is_added_by_the_shorthand_mechanism()
{
    IContainer container = new Container(r => r.For<IAddTypes>().AddInstances(x =>
    {
        x.Type<RedAddTypes>().Named("Red");
        x.Type<GreenAddTypes>().Named("Green");
        x.Type<BlueAddTypes>().Named("Blue");
        x.Type<PurpleAddTypes>();
    }));
    // retrieve the instances by name
    container.GetInstance<IAddTypes>("Red").IsType<RedAddTypes>();
    container.GetInstance<IAddTypes>("Green").IsType<GreenAddTypes>();
    container.GetInstance<IAddTypes>("Blue").IsType<BlueAddTypes>();
}