StructureMap 3.0 is Live

At long last, I pushed a StructureMap 3.0 nuget to the public feed today nearly a full decade after its very first release on SourceForge as the very first production ready IoC container in .Net.   I’d like to personally thank Frank Quednau for all his work on finally making StructureMap PCL compliant.

While this release don’t add a lot of new features, it’s a big step forward for usability and performance and I believe that StructureMap 3.0 will greatly improve the developer experience.  Most importantly, I think the work we’ve done on the 3.0 release has fixed all of the egregious internal flaws that have bothered me for years and *I* feel very good about the shape of the code.

 

What’s Different and/or Improved?

  • The diagnostics and exception messages are much more useful
  • The registration DSL has been greatly streamlined with a hard focus on consistency throughout the API
  • The core library is now PCL compliant and targets .Net 4.0.  So far SM3 has been successfully tested on WP8
  • I have removed strong naming from the public packages to make the world a better place.  I’m perfectly open to creating a parallel signed version of the Nuget, but I’m holding out for a pull request on that one:)
  • Nested container performance and functionality is vastly improved (100X performance in bigger applications!)
  • Xml configuration and the ancient attribute based configuration has been removed.
  • Interception has been completely rewritten with a much better mechanism for applying decorators (a big gripe of mine from 2.5+)
  • Resolving large object graphs is faster
  • The Profile support was completely rewritten and more effective now
  • Child containers (think client specific or feature specific containers)
  • Improvements in the usage of open generics registration for Jimmy Bogard
  • Constructor function selection and lifecycle configuration can be done per Instance (like every other IoC container in the world except for SM <3.0 😦 )
  • Anything that touches ASP.Net HttpContext has been removed to a separate StructureMap.Web nuget.
  • Conventional registration is more powerful now that the configuration model is streamlined and actually useful as a semantic model

 

 

Still to Come:

I’m still working on a new version of the StructureMap website (published with FubuDocs!), but it’s still a work in progress.  Since I desperately want to reduce the time and effort I spend on supporting StructureMap, look for it soon-ish (for real this time).

Someday I’d like to get around to updating my old QCon ’08 talk about lessons learned from a long-lived codebase with all the additional lessons from the past 6 years.

39 thoughts on “StructureMap 3.0 is Live

    1. Quite a bit in the unit test library. Even when I do manage to publish the updated docs, most of the code samples will be pulled out of the unit tests. You might look specifically in the /Samples and /Acceptance folders.

  1. Quickly tried upgrading one of my VSTO projects from 2 to 3.0 but singleton lifecycles all broke… Getting transient lifecycles instead, although I explicitly configure for singletons in the container.

    1. Can you add some context? The singleton lifecyle is very well tested through unit tests in the codebase. Are you using some sort of convention to specify the lifecycle?

      1. No explicit conventions for lifecycles (although I have one, hopefully unrelated convention in place in the said project). I’ll compile & debug with SM source code as soon as I can find the time. Will then see if it’s me doing something stupid or something else (the upgrade is not critical – I very much like working with SM and simply checked to see if I can do an easy upgrade in this particular project. Already used nightly builds in other projects before).

      2. Both of these tests pass:

        [Test]
        public void singletons()
        {
        var c = new Container(x => {
        x.For().Use().Singleton();
        });

        // It’s always the same object instance
        c.GetInstance()
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance());
        }

        [Test]
        public void singletons_2()
        {
        var c = new Container(x =>
        {
        x.For().Singleton().Use();
        });

        // It’s always the same object instance
        c.GetInstance()
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance());
        }

      3. I’ve seen the same issue with SM3, but I just figured it was a difference in registration “semantics”. In SM2.6 the following registers a singleton lifecycle, in SM3 it does not (at least not in my application):

        x.For().Singleton().Use();

        This registers a singleton lifecycle in my application with SM3:

        x.For().Use().SetLifecycleTo(Lifecycles.Singleton);

      4. @Claus,

        Are you sure about that? That syntax didn’t change “For().Singleton()”. The following test passes just fine:

        [Test]
        public void singletons_2()
        {
        var c = new Container(x =>
        {
        x.For().Singleton().Use();
        });

        // It’s always the same object instance
        var original = c.GetInstance();
        original
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance())
        .ShouldBeTheSameAs(c.GetInstance());

        using (var nested = c.GetNestedContainer())
        {
        nested.GetInstance()
        .ShouldBeTheSameAs(original);
        }
        }

        Can you provide some repro steps if it’s not really working?

        – Jeremy

      5. Yes, I’m quite sure, I just double-checked and re-tested. There is a difference between the behavior of .Singleton() and .SetLifecycleTo(Lifecycles.Singleton).

        Perhaps the issue is related to the fact that the singletons I register are factories that get the SM3 container injected in the constructor?

      6. @Claus,

        .Singleton() is syntactical sugar that delegates to setLifecycleTo(Lifecycles.Singleton) behind the scenes.

        Can you move this to a GitHub issue or a the user group with some reproduction steps?

        Thanks,

        Jeremy

  2. registry.SetAllProperties(x => x.OfType());

    which is now

    registry.Policy.SetAllProperties(x => x.OfType());

    does not work for me anymore. The ISession public property is null after the constructor has been constructor.

    1. I reproduced this this morning and I’m looking into it. Other setter policies are working, so I’m really not sure what’s going on here yet.

      Next time though, could you add a GitHub issue instead of a blog comment? And a failing test to repro the bug helps tremendously.

      Thanks,

      Jeremy

    2. Scratch that Dmitry, I’ve got a passing test on that very functionality. Can you provide more contextual information?

      The code below passes:

      public class ClassWithNamedProperties
      {
      public int Age { get; set; }
      public string LastName { get; set; }
      public string FirstName { get; set; }
      public IGateway Gateway { get; set; }
      public IService Service { get; set; }
      }

      [Test]
      public void specify_setter_policy_by_of_type_and_construct_an_object()
      {
      var theService = new ColorService(“red”);

      var container = new Container(x =>
      {
      x.For().Use(theService);
      x.For().Use();

      x.ForConcreteType().Configure.Setter().Is(5);

      x.Policies.SetAllProperties(policy => policy.OfType());
      });

      var description = container.Model.For().Default.DescribeBuildPlan();
      Debug.WriteLine(description);

      var target = container.GetInstance();
      target.Service.ShouldBeTheSameAs(theService);
      target.Gateway.ShouldBeNull();
      }

  3. I cannot create a unit test that shows this problem.

    As you probably know, the ISession is the NHibernate session object. It is registered as follows;

    registry.For[ISession]().Use(ctx => NHibernateConfig.SessionFactory.GetCurrentSession());
    registry.Policy.,SetAllProperties(x => x.OfType[ISession]());

    I am using square brackets instead of angular ones because the blog swallows them.

    The base Web API controller has the following property:

    public ISession Session { get; set; }

    Looking at the StructuremapDependencyResolver class with reflector, it creates a nested container to resolve dependencies.

    I hope this helps.

  4. I just verified that if I use a custom StructuremapDependencyResolver that uses the parent container, it works as expected. So it has got to do with nested containers.

  5. I’ve been using the event aggregator you created for the StoryTeller application for a while but have no idea how to migrate the type interceptor to the new infrastucture in StructureMap V3.

    The old declaration was

    public sealed class EventAggregatorInterceptor : TypeInterceptor
    {
    public object Process(object target, IContext context)
    {
    context.GetInstance().AddListener(target);
    return target;
    }

    public bool MatchesType(Type type)
    {
    return type.ImplementsInterfaceTemplate(typeof(IListener));
    }
    }

    Can you give me any pointers as to how to migrate this?

  6. HI Jeremy!
    I need the strong naming version because the DLLs of my project need to be signed. How can I get a signed version?
    Thanks!

  7. It might just be me, but I am having a very difficult time using the 3.0 version with 0 documentation. I have tried to apply what was in the 2.x documents to 3 and it just doesn’t work. When can we expect some docs!!!

Leave a reply to jeremydmiller Cancel reply