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

Freddy Hansen
Thank you, I had missed the subtle difference here and your post saved me :-)
2012-10-23 18:58 UTC


Wish to comment?

You can add a comment to this post by sending me a pull request. Alternatively, you can discuss this post on Twitter or Google Plus, or somewhere else with a permalink. Ping me with the link, and I may add it as a comment.

Published

Tuesday, 20 July 2010 20:42:53 UTC

Tags



"Our team wholeheartedly endorses Mark. His expert service provides tremendous value."
Hire me!