StructureMap PerRequest vs. Unique lifetimes by Mark Seemann
StructureMap offers several different lifetimes, among these two known as PerRequest and Unique respectively. Recently I found myself wondering what was the difference between those two, but a little help from Jeremy Miller put me on the right track.
In short, Unique is equivalent to what Castle Windsor calls Transient: every time an instance of a type is needed, a new instance is created. Even if we need the same service multiple times in the same resolved graph, multiple instances are created.
PerRequest, on the other hand, is a bit special. Each type can be viewed as a Singleton within a single call to GetInstance, but as Transient across different invocations of GetInstance. In other words, the same instance will be shared within a resolved object graph, but if we resolve the same root type once more, we will get a new shared instance - a Singleton local to that graph.
Here are some unit tests I wrote to verify this behavior (recall that PerRequest is StructureMap's default lifestyle):
[Fact] public void ResolveServicesWithSameUniqueDependency() { var container = new Container(); container.Configure(x => { var unique = new UniquePerRequestLifecycle(); x.For<IIngredient>().LifecycleIs(unique) .Use<Shrimp>(); x.For<OliveOil>().LifecycleIs(unique); x.For<EggYolk>().LifecycleIs(unique); x.For<Vinegar>().LifecycleIs(unique); x.For<IIngredient>().LifecycleIs(unique) .Use<Vinaigrette>(); x.For<IIngredient>().LifecycleIs(unique) .Use<Mayonnaise>(); x.For<Course>().LifecycleIs(unique); }); var c1 = container.GetInstance<Course>(); var c2 = container.GetInstance<Course>(); Assert.NotSame( c1.Ingredients.OfType<Vinaigrette>().Single().Oil, c1.Ingredients.OfType<Mayonnaise>().Single().Oil); Assert.NotSame( c2.Ingredients.OfType<Vinaigrette>().Single().Oil, c2.Ingredients.OfType<Mayonnaise>().Single().Oil); Assert.NotSame( c1.Ingredients.OfType<Vinaigrette>().Single().Oil, c2.Ingredients.OfType<Vinaigrette>().Single().Oil); } [Fact] public void ResolveServicesWithSamePerRequestDependency() { var container = new Container(); container.Configure(x => { x.For<IIngredient>().Use<Shrimp>(); x.For<OliveOil>(); x.For<EggYolk>(); x.For<Vinegar>(); x.For<IIngredient>().Use<Vinaigrette>(); x.For<IIngredient>().Use<Mayonnaise>(); }); var c1 = container.GetInstance<Course>(); var c2 = container.GetInstance<Course>(); Assert.Same( c1.Ingredients.OfType<Vinaigrette>().Single().Oil, c1.Ingredients.OfType<Mayonnaise>().Single().Oil); Assert.Same( c2.Ingredients.OfType<Vinaigrette>().Single().Oil, c2.Ingredients.OfType<Mayonnaise>().Single().Oil); Assert.NotSame( c1.Ingredients.OfType<Vinaigrette>().Single().Oil, c2.Ingredients.OfType<Vinaigrette>().Single().Oil); }
Notice that in both cases, the OliveOil instances are different across two independently resolved graphs (c1 and c2).
However, within each graph, the same OliveOil instance is shared in the PerRequest configuration, whereas they are different in the Unique configuration.
Comments