“Nested Containers” in StructureMap 2.6.1

This is the first of a promised series of blog posts to explain and demonstrate the new features of the StructureMap 2.6 release.  First, in order to use this feature, you absolutely must be on StructureMap 2.6.1 (or 2.5.4).  Your friendly neighborhood Shade Tree Developer introduced a bug into the 2.6.0 codebase that makes this feature screw up the parent container (mea culpa).

I want to start with the new “Nested Container” feature.  In a nutshell, the Nested Container is kind of like a temporary clone of a Container that’s invoked like this:

            // Let’s just say that ObjectFactory.Initialize() has already been

            // called so the main Container is already built and ready

            // to use

            using (IContainer nested = ObjectFactory.Container.GetNestedContainer())

            {

                // pull other objects from the nested

                // container and do work with those services

                var service = nested.GetInstance<IService>();

                service.DoSomething();

            }

What did I do up above?  I simply created a new Container (nested) from an existing Container, then pulled a service from the new nested container, did some work with it, then let the C# “using” block auto magically call the Dispose() method on the new nested container object.  You might be asking, why do I need a second Container?  Well, the nested container has some special properties:

  1. The nested container will track all of the transient objects that it creates.  When the nested container itself is disposed, it will call Dispose() on any of the transient objects that it created.  A normal StructureMap Container does not track the transient objects that it creates (and nor should it IMHO).
  2. The nested container “pulls” all instances scoped as anything but transients (Singletons, HttpContext scoped objects, ThreadLocalStorage scoped objects, etc.) from the parent container.  These objects are not disposed from the nested container.
  3. “Transient” objects are scoped to the nested container.  I’d try to explain that, but why don’t I just show the unit test instead:

        [Test]

        public void transient_service_in_the_parent_container_is_effectively_a_singleton_for_the_nested_container()

        {

            var parent = new Container(x =>

            {

                // IWidget is a “transient”

                x.For<IWidget>().Use<AWidget>();

            });

 

            IContainer child = parent.GetNestedContainer();

 

            var childWidget1 = child.GetInstance<IWidget>();

            var childWidget2 = child.GetInstance<IWidget>();

            var childWidget3 = child.GetInstance<IWidget>();

 

            var parentWidget = parent.GetInstance<IWidget>();

 

            childWidget1.ShouldBeTheSameAs(childWidget2);

            childWidget1.ShouldBeTheSameAs(childWidget3);

            childWidget1.ShouldNotBeTheSameAs(parentWidget);

        }

 

It’s not the most exciting thing in the world, but it’s helpful in some specific scenarios:

  1. Web requests.  Inside a single web request I need every object to access the exact same NHibernate ISession instance (substitute the analogue in your persistence tooling of choice).  At the end of the web request I may want to tear down and dispose all the services created during that web request – i.e. make damn sure the database connection is closed and cleaned up at the end.  I’m not exactly sure how you would use this in ASP.Net MVC (not saying you can’t, just that I haven’t given it much thought), but it’s working out very well for us with a FubuMVC Behavior like I showed here.
  2. Short lived atomic transactions.  We use the nested container within our rules engine.  Within a single NHibernate ISession and transaction block, we create several object graphs with service location calls to the nested container.*  Using the nested container feature made it much simpler for us to “scope” the ISession and even rules state objects within a logical transaction.
  3. User Interface composition.  From a twitter conversation with Glenn Block a couple weeks back.  Let’s say that you have a distinct area of the UI where you have a long running workflow like a wizard that replaces the controls and Presenters / ViewModels currently active.  When those Views, ViewModel’s, and Presenters are created, you probably want those objects to have shared state and layout “region manager” type classes injected into them.  Using a nested container for the wizard is “a” way to build those objects with the proper shared services.

 

Sample Usage

Most of our nested container usage is wrapped up within the class shown below:

    public class TransactionProcessor : ITransactionProcessor

    {

        private readonly object _locker = new object();

        private IContainer _container;

 

        // This IContainer is the parent container from

        // ObjectFactory.Container

        public TransactionProcessor(IContainer container)

        {

            _container = container;

        }

 

        public void Execute<T>(Action<T> action)

        {

            execute(c =>

            {

                var service = c.GetInstance<T>();

                action(service);

            });

        }

 

 

 

        // This code is used in our codebase as a generic way to invoke

        // a service or action within the scope of a nested container

        private void execute(Action<IContainer> action)

        {

            IContainer container = null;

            lock (_locker)

            {

                container = _container;

            }

 

            // ITransactionBoundary is a Dovetail specific interface / class

            // we use just to manage an NHibernate ISession object

            using (IContainer nestedContainer = container.GetNestedContainer())

            {

                var boundary = nestedContainer.GetInstance<ITransactionBoundary>();

                boundary.Start();

                action(nestedContainer);

                boundary.Commit();

            }

        }

    }

In real usage, we invoke services within a transaction with code like this:

            var transaction = ObjectFactory.GetInstance<ITransactionProcessor>();

            transaction.Execute<DataDriver>(x => x.ClearData());

 

 

* Some of you are going to read that sentence and do a kneejerk “…but Ayende says you’re only supposed to do one service locator call in the entire application!”  Don’t do the kneejerk thing without understanding the context.

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in StructureMap. Bookmark the permalink. Follow any comments here with the RSS feed for this post.