Back in 2012, I wrote a post about how to use the decorator pattern with StrutureMap.  Since then, StructureMap 3.0 has been released, and it’s actually much easier to apply decorators now!  Read on, and I’ll show you.

[more]

Back in 2012…

The StructureMap 2.6.x API didn’t provide a clean way to decorate things.  You had to use the EnrichWith method, like so:

var container = new Container(cfg =>
    {
        //...
        
        cfg.For<IProductRepository>()
            .Use<InMemoryProductRepository>()
            .EnrichWith((ctx, r) =>
                {
                    return new ProductRepoLogger(r, ctx.GetInstance<User>());
                });

        //...
    });

var repo = container.GetInstance<IProductRepository>();
//Repo is actually a ProductRepoLogger that wraps an InMemoryProductRepository.

This worked well enough for simple cases, but what if you wanted to chain on more than one decorator? 

var container = new Container(cfg =>
    {
        //...
        
        cfg.For<IProductRepository>()
            .Use<InMemoryProductRepository>()
            .EnrichWith((ctx, r) =>
                {
                    return new ProductRepoLogger(
                        new ProductSecurityDecorator(r, ctx.GetInstance<IProductAuthorizer>(), ctx.GetInstance<User>()), 
                        ctx.GetInstance<User>());
                });

        //...
    });

var repo = container.GetInstance<IProductRepository>();
//Repo is now ProductRepoLogger that wraps a ProductSecurityDecorator that wraps an InMemoryProductRepository.

Ugh.

So, I built an extension method that would allow you to do things in a cleaner way:

var container = new Container(cfg =>
    {
        //...
        
        cfg.For<IProductRepository>().Use<InMemoryProductRepository>()
            .Decorate().With<ProductSecurityDecorator>()
            .AndThen<ProductRepoLogger>()
            .AndThen<RudeProductRepoLogger>();
        cfg.For<IProductAuthorizer>().Use<ProductAuthorizer>();
        
        //...
    });

var repo = container.GetInstance<IProductRepository>();

It took a bit of code, but the result was undeniably easier to read.

But that was 2012…

Now, in 2015…

StructureMap actually provides a way to do this without the need for any custom extension methods:

var container = new Container(cfg =>
                    {
                        cfg.For<User>().Use(currentUser);
                        cfg.For<IProductRepository>().Use<InMemoryProductRepository>();
                        cfg.For<IProductRepository>().DecorateAllWith<ProductSecurityDecorator>();
                        cfg.For<IProductRepository>().DecorateAllWith<ProductRepoLogger>();
                        cfg.For<IProductRepository>().DecorateAllWith<RudeProductRepoLogger>();
                        cfg.For<IProductAuthorizer>().Use<ProductAuthorizer>();
                    });

var repo = container.GetInstance<IProductRepository>();

MUCH better!

If you want the code for this, you can grab it here.   Yes, I know that repo says “ASP.NET samples” and this has nothing to do with ASP.NET, but I didn’t feel like creating a new repo just for this. 🙂