Clean and clear configuration with StructureMap

All sources of this post can be found at my git.

Today, I will continue to sharing some knowledge that I know about StructureMap on Multi-layers application. So I think everyone also know about Multi-layers application, in past we often used the 3 layers (Presentation, Business Logic and Data Access), but by the time maybe we had more than 3 layers as well. In past, when I used Spring.NET framework for IoC container, I must make many configuration in XML file (who knew about XML hell???), it is really terrible. Why? Because it is not a strong type, so very easy to got a error when config an object and also hard to find cause of error in XML file. But now we have DSL for config objects and also have a Fluent Interface for working with config tasks. Some of containers also try to migrate to this way. And I think it is really good to work with. So one question here, how do we config on the multi-layers? Somebody will answer that we will config all instances on the Presentation layer or Service layer in WCF service. Yes, that's fine. And we shall config all instances in these layers.

But when I studied a Divide and Conquer algorithm at University. It is really good for some situation in my life. And in config object for IoC container, I also apply it as well, because I feel that we shall be easy to read and manage object configurations if this config file is small and less code. I did not like some application that config file is very long (maybe more than 1000 line of codes), I called it is code-config hell. A long time ago, I tried to find a best solution for this. And now some of IoCs have supported the feature that permit you to config on many modules and after that it will merge your config to its main container. You can reference to StructureMap, AutoFac, MEF for this. In StructureMap, we have a Registry class; it looks like a part of DSL config for your application. And you can call ObjectFactory to scan alll registries in your application. I love this features. You can imagine that we shall register all configs on modules and after that pass the namspace of these modules to ObjectFactory for scanning. Every object is dynamic. And in AutoFac also have Module class for this purpose. The important thing is code config file will short and clear to read. It make you easy to maintain application in the future (I used to open a code config files in Unity and tried to a instance config inside it, it took me a lot of time). Almost people also know that coding is only 10% and maintain is taking you 90% effort and money you got from maintaining application.

It is enough to talk about the theory and the reasons. Now I will focus on the way that we usually work with StructureMap. And try to make the configuration is well when application boot. Do you know Bootstrapper? Yeah it is great for this situation. I will use it for this post. And I also integrated with Automapper. Wating and see how do it works.

The first thing we need to define the contract for BootStrapper. I have an abstract class for BootStrapper as below:

    public abstract class BootStrapperBase : RootObject
    {
        protected IConfigurator Configurator;

        protected IList<string> AssemblyNames;

        protected BootStrapperBase(IList<string> assemblyNames, IConfigurator configurator)
        {
            AssemblyNames = assemblyNames;
            Configurator = configurator;
        }

        public virtual void BootAllConfig()
        {
        }
    }

And I also have a interface for some tasks that will run inside BootStrapper (one of it, I will implement for run new Profile for Automapper):

    public interface IBootstrapperTask
    {
        void Execute();
    }

And I must have a BootStrapper concrete class for run as:

    public class MyBootStrapper : BootStrapperBase
    {
        private static volatile MyBootStrapper _instance;
        private static readonly object SyncRoot = new Object();

        /// <summary>
        /// http://msdn.microsoft.com/en-us/library/ff650316.aspx
        /// </summary>
        public static MyBootStrapper GetInstance(IList<string> assemblies, IConfigurator configurator)
        {
            Contract.Assert(assemblies != null"List of Registries is null");
            Contract.Assert(assemblies.Count > 0, "List of Registries must be larger than zero");
            Contract.Assert(configurator != null"Configuratorr instance is null");

            if (_instance == null)
            {
                lock (SyncRoot)
                {
                    if (_instance == null)
                        _instance = new MyBootStrapper(assemblies, configurator);
                }
            }

            return _instance;
        }

        private MyBootStrapper() : this(nullnull) { }

        private MyBootStrapper(IList<string> assemblyNames, IConfigurator configurator)
            : base(assemblyNames, configurator)
        {
        }

        public override void BootAllConfig()
        {
            RegisterRegistry();
            RunBootstrapperTasks();
        }

        private void RegisterRegistry()
        {
            CatchExceptionHelper.TryCatchAction(() =>
            {
                ObjectFactory.Initialize(x =>
                {
                    var coreRegistry =
                        (Registry)Activator.CreateInstance(typeof(CoreRegistry));

                    x.AddRegistry(coreRegistry);

                    x.Scan(scan =>
                    {
                        scan.LookForRegistries();

                        foreach (var an in
                            AssemblyNames.Where(an => string.Compare(an, typeof(CoreRegistry).Name) != 0))
                        {
                            scan.Assembly(an);
                        }

                        scan.AddAllTypesOf<IBootstrapperTask>();
                        scan.AddAllTypesOf(typeof(IConsumer<>));
                        scan.WithDefaultConventions();
                    });
                });

                ObjectFactory.AssertConfigurationIsValid();
            }, Logger);
        }

        private static void RunBootstrapperTasks()
        {
            var tasks = MyObjectFactory.GetAllInstances<IBootstrapperTask>();

            if (tasks == nullreturn;
            foreach (var task in tasks)
            {
                task.Execute();
            }
        }
    }

As you see it have a RegisterRegistry method for scan all Registry classes based on list of assemblies that I inject from outside. I also have a RunBootStrapperTasks method for run all the BootStrapper tasks that get from StructureMap container.

Now I will show you the CoreRegistry class as below:

    public class CoreRegistry : Registry
    {
        private readonly ILog _logger;

        public CoreRegistry()
            : this(new MyLogger())
        {
        }

        public CoreRegistry(ILog logger)
        {
            _logger = logger;
            RegisterAllComponents();
        }

        private void RegisterAllComponents()
        {
            CatchExceptionHelper.TryCatchAction(
                () =>
                {
                    For<ILog>().Use<MyLogger>();
                    For<IEventPublisher>().Use<EventPublisher>();
                    For<ISubscriptionService>().Use<EventSubscriptions>();
                    For<IMappingEngine>().Use(() => Mapper.Engine);
                    For<IConfigurator>().Use<Configurator>();

                    For<IAttributeScanEngine>().Use<AutoAttributeScanEngine>();
                    For<IDirectoryTask>().Use<DirectoryWrapper>();
                }, _logger);
        }
    }

CoreRegistry class only contains all instances that need for core application, such as ILog, IEventPublisher, ISubscriptionService, IMappingEngine, IConfigurator...

Now I must implemented a class for wrapping StructureMap's ObjectFactory as here:

    public static class MyObjectFactory
    {
        private static readonly ILog Logger;

        static MyObjectFactory()
        {
            Logger = new MyLogger();
        }

        public static object GetInstance(Type type)
        {
            return LogWriting(() => ObjectFactory.GetInstance(type));
        }

        public static T GetInstance<T>()
        {
            return LogWriting(ObjectFactory.GetInstance<T>);
        }

        public static object GetNamedInstance(Type type, string name)
        {
            return LogWriting(() => ObjectFactory.GetNamedInstance(type, name));
        }

        public static T GetNamedInstance<T>(string name)
        {
            return LogWriting(() => ObjectFactory.GetNamedInstance<T>(name));
        }

        public static IList<T> GetAllInstances<T>()
        {
            return LogWriting(ObjectFactory.GetAllInstances<T>);
        }

        static T LogWriting<T>(Func<T> func)
        {
            try
            {
                return func();
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message);
                throw;
            }
        }
    }

I only wrap some main functions of ObjectFactory.

Some unit testing for test the config file as below:

    [TestClass]
    public class BootstrapperTesting
    {
        protected IList<string> _assemblyNames;
        protected IConfigurator _configurator;

        [TestInitialize]
        public void InitTestCase()
        {
            _assemblyNames = new List<string>
                              {
                                  "ConfORMSample.Core"                              
                              };

            _configurator = new Configurator();

            MyBootStrapper.GetInstance(_assemblyNames, _configurator).BootAllConfig();
        }

        [TestMethod]
        public void Can_Get_Logger_From_Container()
        {
            var logger = MyObjectFactory.GetInstance<ILog>();
            Assert.IsNotNull(logger);
        }

        [TestMethod]
        public void Can_Get_Mapping_Engine_From_Container()
        {
            var mappingEngine = MyObjectFactory.GetInstance<ILog>();
            Assert.IsNotNull(mappingEngine);
        }

        [TestMethod]
        public void Can_Get_Directory_Wrapper_From_Container()
        {
            var directoryWrapper = MyObjectFactory.GetInstance<IDirectoryTask>();
            Assert.IsNotNull(directoryWrapper);
        }

        [TestCleanup]
        public void CleanUpTestCase()
        {
            GC.SuppressFinalize(_configurator);
        }
    }

After that, you can write many Registry classes for you application. As here I just write one Registry class for Repository:

    public class RepositoryRegistry : Registry
    {
        public RepositoryRegistry()
        {
            For<ISpecification<News>>().Use<NewsAddedSpecification>();
            For<INewsRepository>().Use<NewsRepository>();
            For<ICategoryRepository>().Use<CategoryRepository>();
            For<IFootballResultRepository>().Use<FootballResultRepository>();
        }
    }

And when you boot your application you only need config as here:

            _assemblyNames = new List<string>
                              {
                                  "ConfORMSample.Core",
                                  "ConfORMSample.Repository"
                              };

            _configurator = new Configurator();

            MyBootStrapper.GetInstance(_assemblyNames, _configurator).BootAllConfig();

Wrap up: Really I don't talk this is a best way to do with StructureMap. Some people shall not agree with this. So tell me you’re thinking by leave some message below this post. I will be happy to know more about that. Happy coding!

Shout it kick it on DotNetKicks.com

5 Comments

  • Nicely configured procedure with a nice code, thanks for sharing, keep them coming!!..

  • Really good article... I think the Object factory works in as service Locator pattern which is hard to test when used with the other class..eg

    Public class Myclass
    {
    public Myclass()
    {
    Ilogger logger=ObjectFactory.GetInstance()
    }

    }


    How can i mock the Object factory in this Case which is really hard ..

  • Hi satish,

    I will do that as:

    Public class Myclass

    {

    &nbsp; private static readonly Ilogger _logger;

    &nbsp; public Myclass() : this(ObjectFactory.GetInstance&lt;Ilogger&gt;())

    &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp;

    &nbsp; }

    &nbsp; public Myclass(Ilogger logger)

    &nbsp; {

    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_logger=_logger;

    &nbsp; }

    }

    I used default constructor for inject the Ilogger. But it will make you code is dependency to StructureMap, so the best way is you will use is as:

    Public class Myclass

    {

    &nbsp; private static readonly Ilogger _logger;

    &nbsp; public Myclass(Ilogger logger)

    &nbsp; {

    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_logger=_logger;

    &nbsp; }

    }

    With this, you will configure the StructureMap for auto-wiring the ILogger object. This class is not have default constructor, but it is no problems, because CLR will be auto adding this. Thanks for your comment!

  • let me know in7000 sqft ground +1 how to make structure

  • In the tests:
    "
    ...
    var logger = MyObjectFactory.GetInstance();
    ...
    var mappingEngine = MyObjectFactory.GetInstance();"

    Isn't this a mistake (both are getting instance of the ILog)?

Comments have been disabled for this content.