Fork me on GitHub

Try Getting an Optional Service by Plugin Type Edit on GitHub


In normal usage, if you ask StructureMap for a service and StructureMap doesn't recognize the requested type, the requested name, or know what the default should be for that type, StructureMap will fail fast by throwing an exception rather than returning a null. Sometimes though, you may want to retrieve an optional service from StructureMap that may or may not be registered in the Container. If that particular registration doesn't exist, you just want a null value. StructureMap provides first class support for optional dependencies through the usage of the IContainer.TryGetInstance() methods.

Say you have a simple interface IFoo that may or may not be registered in the Container:


public interface IFoo
{
}

public class Foo : IFoo
{
}


In your own code you might request the IFoo service like the code below, knowing that you'll take responsibility yourself for building the IFoo service if StructureMap doesn't have a registration for IFoo:


public class MyFoo : IFoo
{
}

[Fact]
public void real_usage()
{
    var container = new Container();

    // if the container doesn't know about it,
    // I'll build it myself
    var foo = container.TryGetInstance<IFoo>()
              ?? new MyFoo();
}


Just to make this perfectly clear, if StructureMap has a default registration for IFoo, you get this behavior:


[Fact]
public void i_have_got_that()
{
    var container = new Container(_ => _.For<IFoo>().Use<Foo>());

    container.TryGetInstance<IFoo>()
        .ShouldNotBeNull();

    // -- or --

    container.TryGetInstance(typeof(IFoo))
        .ShouldNotBeNull();
}


If StructureMap knows nothing about IFoo, you get a null:


[Fact]
public void i_do_not_have_that()
{
    var container = new Container();

    container.TryGetInstance<IFoo>()
        .ShouldBeNull();

    // -- or --

    container.TryGetInstance(typeof(IFoo))
        .ShouldBeNull();
}


Concrete Types

Since it's not a perfect world, there are some gotchas you need to be aware of. While StructureMap will happily auto-resolve concrete types that aren't registered, that does not apply to the TryGetInstance mechanism:


public class ConcreteThing
{
}

[Fact]
public void no_auto_resolution_of_concrete_types()
{
    var container = new Container();

    container.TryGetInstance<ConcreteThing>()
        .ShouldBeNull();

    // now register ConcreteThing and do it again
    container.Configure(_ => { _.For<ConcreteThing>().Use<ConcreteThing>(); });

    container.TryGetInstance<ConcreteThing>()
        .ShouldNotBeNull();
}


Optional Generic Types

If you are using open generic types, the TryGetInstance() mechanism can close the open generic registration to satisfy the optional dependency like this sample:


public interface IThing<T>
{
}

public class Thing<T> : IThing<T>
{
}

[Fact]
public void can_try_get_open_type_resolution()
{
    var container = new Container(_ => { _.For(typeof(IThing<>)).Use(typeof(Thing<>)); });

    container.TryGetInstance<IThing<string>>()
        .ShouldBeOfType<Thing<string>>();
}