StructureMap – Try geting an optional service

We are just testing on this article one of the StructureMap features which is trying to get optinal service by plugin type and instance name

First, think about we had an IFoo interface and a Foo class which implements an IFoo.

public interface IFoo
{
    string InstanceName { get; }
}

public class Foo : IFoo
{
    public string InstanceName { get; private set; }
    public Foo(string instanceName)
    {
        InstanceName = "Default";
        if (!string.IsNullOrEmpty(instanceName))
        {
            InstanceName = instanceName;
        }
    }
}

After that, we just want to test TryGetInstance method to get service. If registration is not defined in container, we just expecting get null reference.

For plugin types, it is ok, but what if we try to get service instance of concrete type which is not registered current container.For testing this lets define concrete type and don’t register in container.

public class SomethingConcrete
{
    public int Id { get; set; }
    public SomethingConcrete()
    {
        Id = 1;
    }

    public override string ToString()
    {
        return string.Format("Id: {0}", Id);
    }
}

After defining plugin types and concretes, lets try it.

using System;
using StructureMap;

namespace TryGetInstance
{
    class Program
    {
        static void Main(string[] args)
        {
            var container = new Container(_ =>
            {
                //_.For<IFoo>().Use<Foo>().Ctor<string>().Is("");
                _.For<IFoo>().Add<Foo>().Named("fooA").Ctor<string>().Is("fooA instance");
                _.For<IFoo>().Add<Foo>().Named("fooB").Ctor<string>().Is("fooB instance");
            });

            // there is two service instance in container named fooA and fooB
            // and if we dont give a registry for<IFoo> -> use(Foo) TryGetInstance could not give someone
            var foo = container.TryGetInstance<IFoo>();

            // try geting an optional service by plugin type and name
            var fooA = container.TryGetInstance<IFoo>("fooA");

            // if we use 'TryGetInstance' container returns null service.
            var concrete = container.TryGetInstance<SomethingConcrete>();

            // we didnt register it, but we get the service via 'GetInstance'!
            // and this works only concrete types services.
            var concreteAbsolute = container.GetInstance<SomethingConcrete>();

            Console.WriteLine(foo != null ? 
                string.Format("foo exists and its name is: {0}", foo.InstanceName) : 
                "foo null");
            Console.WriteLine(fooA != null ? 
                string.Format("fooA exists and its name is: {0}", fooA.InstanceName) : 
                "fooA null");
            Console.WriteLine(concrete != null ? 
                concrete.ToString() : 
                "concrete is null");
            Console.WriteLine(concreteAbsolute != null ? 
                string.Format("concreteAbsolute exists and it has: {0}", concreteAbsolute.ToString()) : 
                "concreteAbsolute is null");
            Console.WriteLine("--------------------------------------------------------");
            Console.WriteLine(container.Model.For<SomethingConcrete>().Default.DescribeBuildPlan());
            Console.WriteLine("--------------------------------------------------------");
            Console.WriteLine(container.Model.For<IFoo>().Default?.DescribeBuildPlan());
        }
    }
}

If you run the project with these configurations, you will see the GetInstance() method works fine for unregistered concrete type. Because, StructureMap could automatically resolve concrete types. But for resolving a concrete type these rules have to be served;

  • Concrete type must have at least one public constructor.
  • If this constructor has arguments which are another concrete type, these parameter types also must have at least one public ctors. Because StructureMap will try to create instance for each parameter type.
  • The concrete type which has one public ctor and this ctor has a primitive parameter(string, int, datetime) could not be auto resolved by StructureMap. Because StructureMap assumes those types not resolvable.