StructureMap Registry Convention – How To Find Specific Registries

In StructureMap’s default assembly scanner, there’s a LookForRegistries method.  What exactly does this do?  Well, all it does is eventually call Convention<T> using the default registry convention build into StructureMap.  The interface is IRegistrationConvention–easy enough.

Since in my case, I wanted to use a marker interface for the registries that I wanted my container to pull in, I first defined that.


    ///
    /// Marker interface for registries that contain security DSL configuration
    ///
    public interface ISecurityRegistry
    {
    }

I still like the explicit nature of the LookForRegistries method, so I then created an extension method for the assembly scanner.


internal static class AssemblyScannerExtensions
{
/// <summary>
/// Looks for registries using the registry convention specified
/// </summary>
/// <typeparam name="T">The type of registration convention</typeparam>
/// <param name="scanner">The scanner</param>
public static void LookForRegistries<T>(this IAssemblyScanner scanner) where T : IRegistrationConvention, new()
{
scanner.Convention<T>();
}
}

Next, I defined my convention. Now, I did look at the default registry convention, and used some of simple type checks so the convention could easily knockout types that weren’t registries.


    ///
    /// Custom registry convention that will only import in registries that are marked with
    ///
    internal sealed class SecurityRegistryConvention : IRegistrationConvention
    {
        public void Process(Type type, Registry registry)
        {
            if (IsSecurityRegistry(type))
            {
                registry.Configure(x => x.ImportRegistry(type));
            }
        }

        private bool IsSecurityRegistry(Type type)
        {
            if (type.Assembly == typeof(Registry).Assembly)
            {
                return false;
            }

            if (!typeof(Registry).IsAssignableFrom(type))
            {
                return false;
            }

            if (!typeof (ISecurityRegistry).IsAssignableFrom(type))
            {
                return false;
            }

            if (type.IsInterface || type.IsAbstract || type.IsGenericType)
            {
                return false;
            }

            return (type.GetConstructor(new Type[0]) != null);
        }

    }

Finally, my container used the convention with the extension method. You don’t want to call LookForRegistries since that will end up using the default registry convention, and you’ll end up getting registries that don’t have the marker interface.

I think it came together nicely.

var container = new Container(c =>
{
	c.AddRegistry<DefaultRegistry>();
	c.Scan(s =>
	{
		s.AssembliesFromApplicationBaseDirectory();
		s.LookForRegistries<SecurityRegistryConvention>();
	});
});
return container;