“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.
  • Van

    I love the nested container.
    I used it for scope based DI.

    Basically, there are cases when the DI container has to be aware of the scope it’s in. With nested container, I can now deploy DI into these scopes.

    Simple example:
    Let’s take Word for example.

    Word has IFileSaveService to allow the UI to save the file. The service is at global scope.

    Word also have ITextFormatService, which keeps track of format of the text at cursor position. This service must be at document scope, so that it will not affect other documents.

    With nested container, scoped container is now so much easier.

  • http://realfiction.net Frank Quednau

    More abstract: A nested container can be subject to additional configuration via “Configure”, which allows you to overwrite dependencies that are already stated in the parent container for the scope of the nexted container.

  • Jacob

    Why the lock? How can the container reference change.

  • flipdoubt

    Interested in using nested containers to build a composite UI as per the third usage scenario, but the using clause disposes of my controls as I take them out of the nested container. Can you point to further examples of this? Is the best work around to (a) not use the using clause or (b) scope the objects so they are not disposed by the nested container? Thanks.

  • http://www.backlinkschecker.ws/backlinks/buylinks.html Purchase High PR Backlink

    wow great! Thx for sharing this  

  • ms007

    finally i got it. If you use the nested container in the composition root, and pass all of your dependencies to your services (i’m trying not to use StructureMap as a ServiceLocator), then all is proper disposed at the end of the request. What a great thing, this nested container. Looking forward for the version 3.0 of StructureMap.