Skip to content
On this page

Policies

Lamar offers some mechanisms to conventionally determine missing registrations at runtime or apply some fine-grained control over how services are constructed. All of these mechanisms are available under the ServiceRegistry.Policies property when configuring a Lamar container.

For more information on type scanning conventions, see auto-registration and conventions

Auto Resolve Missing Services

INFO

These policies are only evaluated the first time that a particular service type is requested through the container.

Lamar has a feature to create missing service registrations at runtime based on pluggable rules using the new IFamilyPolicy interface:

cs
public interface IFamilyPolicy : ILamarPolicy
{
    /// <summary>
    ///     Allows you to create missing registrations for an unknown service type
    ///     at runtime.
    ///     Return null if this policy does not apply to the given type
    /// </summary>
    ServiceFamily Build(Type type, ServiceGraph serviceGraph);
}

snippet source | anchor

Internally, if you make a request to IContainer.GetInstance(type) for a type that the active Container does not recognize, StructureMap will next try to apply all the registered IFamilyPolicy policies to create a ServiceFamily object for that service type that models the registrations for that service type, including the default, additional named instances, interceptors or decorators, and lifecycle rules.

The simplest built in example is the EnumerablePolicy shown below that can fill in requests for IList<T>, ICollection<T>, and T[] with a collection of all the known registrations of the type T:

cs
internal class EnumerablePolicy : IFamilyPolicy
{
    public ServiceFamily Build(Type type, ServiceGraph serviceGraph)
    {
        if (type.IsArray)
        {
            var instanceType = typeof(ArrayInstance<>).MakeGenericType(type.GetElementType());
            var instance = Activator.CreateInstance(instanceType, type).As<Instance>();
            return new ServiceFamily(type, new IDecoratorPolicy[0], instance);
        }

        if (type.IsEnumerable())
        {
            var elementType = type.GetGenericArguments().First();

            var instanceType = typeof(ListInstance<>).MakeGenericType(elementType);
            var ctor = instanceType.GetConstructors().Single();
            var instance = ctor.Invoke(new object[] { type }).As<Instance>();

            return new ServiceFamily(type, new IDecoratorPolicy[0], instance);
        }

        return null;
    }
}

snippet source | anchor

The result of EnumerablePolicy in action is shown by the acceptance test below:

cs
[Fact]
public void collection_types_are_all_possible_by_default()
{
    // NOTE that we do NOT make any explicit registration of
    // IList<IWidget>, IEnumerable<IWidget>, ICollection<IWidget>, or IWidget[]
    var container = new Container(_ =>
    {
        _.For<IWidget>().Add<AWidget>();
        _.For<IWidget>().Add<BWidget>();
        _.For<IWidget>().Add<CWidget>();
    });

    // IList<T>
    container.GetInstance<IList<IWidget>>()
        .Select(x => x.GetType())
        .ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));

    // ICollection<T>
    container.GetInstance<ICollection<IWidget>>()
        .Select(x => x.GetType())
        .ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));

    // Array of T
    container.GetInstance<IWidget[]>()
        .Select(x => x.GetType())
        .ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));
}

snippet source | anchor

For another example, consider this example from the Lamar unit tests. Say you have a service that looks like this:

cs
public class Color
{
    public string Name { get; set; }
}

snippet source | anchor

And you build a policy that auto-resolves registrations for the Color service if none previously exist:

cs
public class ColorPolicy : IFamilyPolicy
{
    public ServiceFamily Build(Type type, ServiceGraph serviceGraph)
    {
        if (type != typeof(Color))
        {
            return null;
        }

        return new ServiceFamily(type, serviceGraph.DecoratorPolicies,
            ObjectInstance.For(new Color { Name = "Red" }).Named("Red"),
            ObjectInstance.For(new Color { Name = "Blue" }).Named("Blue"),
            ObjectInstance.For(new Color { Name = "Green" }).Named("Green")
        );
    }
}

snippet source | anchor

You can register the new ColorPolicy shown above like this:

cs
var container = Container.For(_ => { _.Policies.OnMissingFamily<ColorPolicy>(); });

snippet source | anchor

Internally, Lamar uses this IFamilyPolicy feature for its generic type support, the enumerable type support described as above, and the auto registration of concrete types.

Instance Construction Policies

Lamar allows you to create conventional build policies with a mechanism for altering how object instances are built based on user created meta-conventions using the IInstancePolicy shown below:

cs
/// <summary>
///     Custom policy on Instance construction that is evaluated
///     as part of creating a "build plan"
/// </summary>
public interface IInstancePolicy : ILamarPolicy
{
    /// <summary>
    ///     Apply any conventional changes to the configuration
    ///     of a single Instance
    /// </summary>
    /// <param name="instance"></param>
    void Apply(Instance instance);
}

snippet source | anchor

These policies are registered as part of the ServiceRegistry DSL with the Policies.Add() method:

cs
var container = new Container(_ =>
{
    _.Policies.Add<MyCustomPolicy>();
    // or
    _.Policies.Add(new MyCustomPolicy());
});

snippet source | anchor

cs
var container = new Container(_ =>
{
    _.Policies.Add<MyCustomPolicy>();
    // or
    _.Policies.Add(new MyCustomPolicy());
});

snippet source | anchor

The IInstancePolicy mechanism probably works differently than other IoC containers in that the policy is applied to the container's underlying configuration model instead of at runtime. Internally, StructureMap lazily creates a "build plan" for each configured Instance at the first time that that Instance is built or resolved. As part of creating that build plan, StructureMap runs all the registered IInstancePolicy objects against the Instance in question to capture any potential changes before "baking" the build plan into a .Net Expression that is then compiled into a Func for actual construction.

The Instance objects will give you access to the types being created, the configured name of the Instance (if any), the ability to add interceptors and to modify the lifecycle. If you wish to add inline dependencies to Instances that are built by calling constructor function and setter properties, you may find it easier to use the ConfiguredInstancePolicy base class as a convenience:

cs
/// <summary>
///     Base class for using policies against IConfiguredInstance registrations
/// </summary>
public abstract class ConfiguredInstancePolicy : IInstancePolicy
{
    public void Apply(Instance instance)
    {
        if (instance is IConfiguredInstance)
        {
            apply(instance.As<IConfiguredInstance>());
        }
    }

    protected abstract void apply(IConfiguredInstance instance);
}

snippet source | anchor

For more information, see:

Example 1: Constructor arguments

So let me say upfront that I don't like this approach, but other folks have asked for this ability over the years. Say that you have some legacy code where many concrete classes have a constructor argument called "connectionString" that needs to be the connection string to the application database like these classes:

cs
public class DatabaseUser
{
    public DatabaseUser(string connectionString)
    {
        ConnectionString = connectionString;
    }

    public string ConnectionString { get; set; }
}

public class ConnectedThing
{
    public ConnectedThing(string connectionString)
    {
        ConnectionString = connectionString;
    }

    public string ConnectionString { get; set; }
}

snippet source | anchor

cs
public class DatabaseUser
{
    public string ConnectionString { get; set; }

    public DatabaseUser(string connectionString)
    {
        ConnectionString = connectionString;
    }
}

public class ConnectedThing
{
    public string ConnectionString { get; set; }

    public ConnectedThing(string connectionString)
    {
        ConnectionString = connectionString;
    }
}

snippet source | anchor

Instead of explicitly configuring every single concrete class in StructureMap with that inline constructor argument, we can make a policy to do that in one place:

cs
public class ConnectionStringPolicy : ConfiguredInstancePolicy
{
    protected override void apply(IConfiguredInstance instance)
    {
        var parameter = instance.ImplementationType
            .GetConstructors()
            .SelectMany(x => x.GetParameters())
            .FirstOrDefault(x => x.Name == "connectionString");

        if (parameter != null)
        {
            var connectionString = findConnectionStringFromConfiguration();
            instance.Ctor<string>(parameter.Name).Is(connectionString);
        }
    }

    // find the connection string from whatever configuration
    // strategy your application uses
    private string findConnectionStringFromConfiguration()
    {
        return "the connection string";
    }
}

snippet source | anchor

cs
public class ConnectionStringPolicy : ConfiguredInstancePolicy
{
    protected override void apply(Type pluginType, IConfiguredInstance instance)
    {
        var parameter = instance.Constructor.GetParameters().FirstOrDefault(x => x.Name == "connectionString");
        if (parameter != null)
        {
            var connectionString = findConnectionStringFromConfiguration();
            instance.Dependencies.AddForConstructorParameter(parameter, connectionString);
        }
    }

    // find the connection string from whatever configuration
    // strategy your application uses
    private string findConnectionStringFromConfiguration()
    {
        return "the connection string";
    }
}

snippet source | anchor

Now, let's use that policy against the types that need "connectionString" and see what happens:

cs
[Fact]
public void use_the_connection_string_policy()
{
    var container = new Container(_ => { _.Policies.Add<ConnectionStringPolicy>(); });

    container.GetInstance<DatabaseUser>()
        .ConnectionString.ShouldBe("the connection string");

    container.GetInstance<ConnectedThing>()
        .ConnectionString.ShouldBe("the connection string");
}

snippet source | anchor

cs
[Fact]
public void use_the_connection_string_policy()
{
    var container = new Container(_ =>
    {
        _.Policies.Add<ConnectionStringPolicy>();
    });

    container.GetInstance<DatabaseUser>()
        .ConnectionString.ShouldBe("the connection string");

    container.GetInstance<ConnectedThing>()
        .ConnectionString.ShouldBe("the connection string");
}

snippet source | anchor

Years ago StructureMap was knocked by an "IoC expert" for not having this functionality. I said at the time -- and still would -- that I would strongly recommend that you simply don't directly open database connections in more than one or a very few spots in your code anyway. If I did need to configure a database connection string in multiple concrete classes, I prefer strong typed configuration.

Example 2: Connecting to Databases based on Parameter Name

From another common user request over the years, let's say that your application needs to connect to multiple databases, but your data access service in both cases is an interface called IDatabase, and that's all the consumers of any database should ever need to know.

To make this concrete, let's say that our data access is all behind an interface and concrete class pair named Database/IDatabase like so:

cs
public interface IDatabase
{
}

public class Database : IDatabase
{
    public Database(string connectionString)
    {
        ConnectionString = connectionString;
    }

    public string ConnectionString { get; set; }

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

snippet source | anchor

cs
public interface IDatabase { }

public class Database : IDatabase
{
    public string ConnectionString { get; set; }

    public Database(string connectionString)
    {
        ConnectionString = connectionString;
    }

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

snippet source | anchor

For a registration policy, let's say that the parameter name of an IDatabase dependency in a constructor function should match an identifier of one of the registered IDatabase services.

That policy would be:

cs
public class InjectDatabaseByName : ConfiguredInstancePolicy
{
    protected override void apply(IConfiguredInstance instance)
    {
        var parameterInfos = instance.ImplementationType.GetConstructors()
            .SelectMany(x => x.GetParameters())
            .Where(x => x.ParameterType == typeof(IDatabase));

        foreach (var param in parameterInfos)
            // Using ReferencedInstance here tells Lamar
            // to "use the IDatabase by this name"
            instance.Ctor<IDatabase>(param.Name).IsNamedInstance(param.Name);
    }
}

snippet source | anchor

cs
public class InjectDatabaseByName : ConfiguredInstancePolicy
{
    protected override void apply(Type pluginType, IConfiguredInstance instance)
    {
        instance.Constructor.GetParameters()
            .Where(x => x.ParameterType == typeof(IDatabase))
            .Each(param =>
            {
                // Using ReferencedInstance here tells StructureMap
                // to "use the IDatabase by this name"
                var db = new ReferencedInstance(param.Name);
                instance.Dependencies.AddForConstructorParameter(param, db);
            });
    }
}

snippet source | anchor

And because I'm generally pretty boring about picking test data names, let's say that two of our databases are named "red" and "green" with this container registration below:

cs
var container = new Container(_ =>
{
    _.For<IDatabase>().Add<Database>().Named("red")
        .Ctor<string>("connectionString").Is("*red*");

    _.For<IDatabase>().Add<Database>().Named("green")
        .Ctor<string>("connectionString").Is("*green*");

    _.Policies.Add<InjectDatabaseByName>();
});

snippet source | anchor

cs
var container = new Container(_ =>
{
    _.For<IDatabase>().Add<Database>().Named("red")
        .Ctor<string>("connectionString").Is("*red*");

    _.For<IDatabase>().Add<Database>().Named("green")
        .Ctor<string>("connectionString").Is("*green*");

    _.Policies.Add<InjectDatabaseByName>();
});

snippet source | anchor

For more context, the classes that use IDatabase would need to have constructor functions like these below:

cs
public class BigService
{
    public BigService(IDatabase green)
    {
        DB = green;
    }

    public IDatabase DB { get; set; }
}

public class ImportantService
{
    public ImportantService(IDatabase red)
    {
        DB = red;
    }

    public IDatabase DB { get; set; }
}

public class DoubleDatabaseUser
{
    public DoubleDatabaseUser(IDatabase red, IDatabase green)
    {
        Red = red;
        Green = green;
    }

    // Watch out for potential conflicts between setters
    // and ctor params. The easiest thing is to just make
    // setters private
    public IDatabase Green { get; }

    public IDatabase Red { get; }
}

snippet source | anchor

cs
public class BigService
{
    public BigService(IDatabase green)
    {
        DB = green;
    }

    public IDatabase DB { get; set; }
}

public class ImportantService
{
    public ImportantService(IDatabase red)
    {
        DB = red;
    }

    public IDatabase DB { get; set; }
}

public class DoubleDatabaseUser
{
    public DoubleDatabaseUser(IDatabase red, IDatabase green)
    {
        Red = red;
        Green = green;
    }

    // Watch out for potential conflicts between setters
    // and ctor params. The easiest thing is to just make
    // setters private
    public IDatabase Green { get; private set; }

    public IDatabase Red { get; private set; }
}

snippet source | anchor

Finally, we can exercise our new policy and see it in action:

cs
// ImportantService should get the "red" database
container.GetInstance<ImportantService>()
    .DB.As<Database>().ConnectionString.ShouldBe("*red*");

// BigService should get the "green" database
container.GetInstance<BigService>()
    .DB.As<Database>().ConnectionString.ShouldBe("*green*");

// DoubleDatabaseUser gets both
var user = container.GetInstance<DoubleDatabaseUser>();

user.Green.As<Database>().ConnectionString.ShouldBe("*green*");
user.Red.As<Database>().ConnectionString.ShouldBe("*red*");

snippet source | anchor

cs
// ImportantService should get the "red" database
container.GetInstance<ImportantService>()
    .DB.As<Database>().ConnectionString.ShouldBe("*red*");

// BigService should get the "green" database
container.GetInstance<BigService>()
    .DB.As<Database>().ConnectionString.ShouldBe("*green*");

// DoubleDatabaseUser gets both
var user = container.GetInstance<DoubleDatabaseUser>();

user.Green.As<Database>().ConnectionString.ShouldBe("*green*");
user.Red.As<Database>().ConnectionString.ShouldBe("*red*");

snippet source | anchor

How I prefer to do this - my strong preference would be to use separate interfaces for the different databases even if that type is just an empty type marker that implements the same base. I feel like using separate interfaces makes the code easier to trace and understand than trying to make StructureMap vary dependencies based on naming conventions or what namespace a concrete type happens to be in. At least now though, you have the choice of my way or using policies based on naming conventions.

Example 3: Make objects singletons based on type name

Unlike the top two examples, this is taken from a strategy that I used in FubuMVC for its service registration. In that case, we wanted any concrete type whose name ended with "Cache" to be a singleton in the container registration. With the new IInstancePolicy feature in StructureMap 4, we could create a new policy class like so:

cs
public class CacheIsSingleton : IInstancePolicy
{
    public void Apply(Instance instance)
    {
        if (instance.ImplementationType.Name.EndsWith("Cache"))
        {
            instance.Lifetime = ServiceLifetime.Singleton;
        }
    }
}

snippet source | anchor

cs
public class CacheIsSingleton : IInstancePolicy
{
    public void Apply(Type pluginType, Instance instance)
    {
        if (instance.ReturnedType.Name.EndsWith("Cache"))
        {
            instance.SetLifecycleTo<SingletonLifecycle>();
        }
    }
}

snippet source | anchor

Now, let's say that we have an interface named IWidgets and a single implementation called WidgetCache that should track our widgets in the application. Using our new policy, we should see WidgetCache being made a singleton:

cs
[Fact]
public void set_cache_to_singleton()
{
    var container = new Container(_ =>
    {
        _.Policies.Add<CacheIsSingleton>();

        _.For<IWidgets>().Use<WidgetCache>();
    });

    // The policy is applied *only* at the time
    // that StructureMap creates a "build plan"
    container.GetInstance<IWidgets>()
        .ShouldBeSameAs(container.GetInstance<IWidgets>());

    // Now that the policy has executed, we
    // can verify that WidgetCache is a SingletonThing
    container.Model.For<IWidgets>().Default
        .Lifetime.ShouldBe(ServiceLifetime.Singleton);
}

snippet source | anchor

cs
[Fact]
public void set_cache_to_singleton()
{
    var container = new Container(_ =>
    {
        _.Policies.Add<CacheIsSingleton>();

        _.For<IWidgets>().Use<WidgetCache>();
    });

    // The policy is applied *only* at the time
    // that StructureMap creates a "build plan"
    container.GetInstance<IWidgets>()
        .ShouldBeTheSameAs(container.GetInstance<IWidgets>());

    // Now that the policy has executed, we
    // can verify that WidgetCache is a SingletonThing
    container.Model.For<IWidgets>().Default
        .Lifecycle.ShouldBeOfType<SingletonLifecycle>();
}

snippet source | anchor