Fork me on GitHub

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

Note! 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:


public interface IFamilyPolicy : ILamarPolicy
{
    ServiceFamily Build(Type type, ServiceGraph serviceGraph);
}

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 plugin type that models the registrations for that plugin 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:


public 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;
    }
}

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


[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));
}

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


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

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


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")
            
            
            );
    }
}

You can register the new ColorPolicy shown above like this:


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

Internally, Lamar uses this IFamilyPolicy feature for its generic type support, the enumerable type support described a 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:



public interface IInstancePolicy : ILamarPolicy
{
    void Apply(Instance instance);
}

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


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

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:


public abstract class ConfiguredInstancePolicy : IInstancePolicy
{
    public void Apply(Instance instance)
    {
        if (instance is IConfiguredInstance)
        {
            apply(instance.As<IConfiguredInstance>());
        }
    }

    protected abstract void apply(IConfiguredInstance instance);
}

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:


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;
    }
}

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:


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";
    }
}

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


[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");
}

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:


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);
    }
}

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:


public class InjectDatabaseByName : ConfiguredInstancePolicy
{
    protected override void apply(IConfiguredInstance instance)
    {
        instance.ImplementationType.GetConstructors()
            .SelectMany(x => x.GetParameters())
            .Where(x => x.ParameterType == typeof(IDatabase))
            .Each(param =>
            {
                // Using ReferencedInstance here tells Lamar
                // to "use the IDatabase by this name"
                instance.Ctor<IDatabase>(param.Name).IsNamedInstance(param.Name);
            });
    }
}

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:


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>();
});

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


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; }
}

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


// 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*");

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:


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

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:

[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);
}