Dependency Inversion for Dummies: Unity and StructureMap

by Ben Hart 20. November 2008 14:55

This is it. The moment you've been waiting for. The series that has you periodically checking back to see if there is another instalment continues (since the frequency of my posts has you questioning whether the feed is working). Dependency Inversion for Dummies is back...

Previously...

When we started on this journey, early on, we were empowered with the knowledge of how insidious dependencies can cripple an application's ability to change. Despite this alarming revelation, in the spirit of developers knowing that the time of failed software projects must change, we read on. Yes we can.

Rather than despair at this new knowledge we considered that a simple means to reduce this restrictive coupling is constructor injection. We struggled through references to teen chick-rock, arrogant comparisons to blockbuster TV-Series, bad examples, always seeking this better way. Yes we can.

When we then discovered that inverting our dependencies can make for more work in object creation, rather than walking away and dismissing this as a fad, we took the high road to find out how centralising object creation can help. Yes we can.

When all seemed lost, when the temptation to ignore the breakthroughs of those that came before us began to overwhelm our new sensibilities, we learned that factories or service locators are not only simple concepts, but remarkably easy to implement and use. Yes we can.

And, when promises of a follow-up were not kept, and when a week became a fortnight, a month, more, did we lose faith in the value of this blog, or did we stand up, with resolve and patience, and understand that Ben Hart is an African, and that in Africa, we work on African Time?

Unity and StructureMapYes we did

Today we use some tools, and compare them with the simplest of all requirements. This will not be a comparison of features, nor an evaluation of any sort. Don't leave this settled on an IoC container without investigating them yourself. Take a look at least at Autofac, Ninject, Windsor and Spring.NET before you make up your mind. Choose the one that works for you, while all similar in the basics, they all bring something different to the party (some bring the whole bar!).

Today we're just going to look at the tool I use against the one released by Microsoft. The Apache 2 OSS against the MPL. The industry veteran against the newcomer. Hulk Hogan against Toa.

 [While I generally don't care much for what people think of me, the thought that anyone might assume that I knew who Toa was before this blog post is too much to bear. This was merely the first image result that had an oldie of WWF (in my time, the kids call it WWE these days) with a newcomer. That's my story, and I'm sticking to it.]

Where's the code?

Remember last time we had centralised object creation into a simple service locator. It wasn't all that pretty. It was called by a simple console application that requested an instance of the ITagService in order to retrieve tags. The whole application fits into this tiny box:

class Program
{
    static void Main(string[] args)
    {
        ITagService tagService = ServiceLocator.GetInstance<ITagService>();
        foreach (string tag in tagService.GetUniqueTags())
        {
            Console.WriteLine(tag);
        }
        Console.ReadLine();
    }
}
 
public static class ServiceLocator
{
    public static T GetInstance<T>()
    {
        return (T)GetInstance(typeof(T));
    }
    public static object GetInstance(Type type)
    {
        return GetInstance(type.Name);
    }
    public static object GetInstance(string name)
    {
        switch (name)
        {
            case "ITagService":
                return new UniqueTagService(new TagDatabase());
        }
        throw new ArgumentOutOfRangeException("name", string.Format("{0} is not a registered type.", name));
    }
}
 
public interface ITagService
{
    IList<string> GetUniqueTags();
    int TagCount();
}
 
public class UniqueTagService : ITagService
{
    private ITagData _db;
 
    public UniqueTagService(ITagData database)
    {
        _db = database;
    }
 
    public IList<string> GetUniqueTags()
    {
        return new List<string>(_db.GetTags().Distinct());
    }
 
    public int TagCount()
    {
        return _db.GetTags().Length;
    }
}
 
public interface ITagData
{
    string[] GetTags();
}
 
public class TagDatabase : ITagData
{
    private string[] _tags = new[] { "Word1", "Word2", "Word3", "Word1" };
 
    public string[] GetTags()
    {
        return _tags;
    }
}

Rather than change much else, we're simply going to extend the service locator to use the new tools in our belt. Notice that our client code is only calling the generic GetInstance<T> method, the overloads were simply to confuse you. So, without any further ado, let's meet our contestants.

First into the ring: the drum beater, the system cheater, the broadcaster, the drummer... can a get a shout out fooooooorrrrrrrr.......

StructureMap

First up you'll need to download the latest binaries from the sourceforge site and add a reference to StructureMap.dll. While there are other means to configure, the easiest has to be the internal dsl. The simplest means to use this is the creation of a registry file, and the override of the configure() method.

public class MyRegistry : Registry
{
    protected override void configure()
    {
        ForRequestedType<ITagService>().TheDefaultIsConcreteType<UniqueTagService>();
        ForRequestedType<ITagData>().TheDefaultIsConcreteType<TagDatabase>();
    }
}

All we've really done here is mapped the implementation we desire to the type that will be requested. Next thing is to let StructureMap know about the registry, and wire it into our service locator.

public static class ServiceLocator
{
    static ServiceLocator()
    {
        ObjectFactory.Initialize(c => c.AddRegistry(new MyRegistry()));
    }
    public static T GetInstance<T>()
    {
        return ObjectFactory.GetInstance<T>();
    }
}

For simplicities sake I've called ObjectFactory.Initialize() from the static constructor of our already static service locator. You'd generally only want to call this once in an application, and this achieves this. Note the lambda adds the registry to the object factory, and that our GetInstance<T> defers to the factory.  That's all that's required. (Note also that having the service locator wrapping the IoC container is not something I'd recommend, rather just a means to continue without changing any more code.)

More astute readers may wonder HTF this works? All we've requested is the ITagService. ITagService has a dependency to ITagData, previously we had to instantiate the TagDataBase and pass it in. WTF is going on here?

That, my friends, is the beauty of auto-wiring. StructureMap takes it upon itself to examine the requested type for dependencies, and creates and passes those in when requested. Just don't forget to say thank you.

Well that was pretty simple. Now the one I've been l've been waiting for. The one I've been meaning to look at for ages. The one that at first appalled me as a senseless waste of resources when the existing alternatives were so plentiful. The one that will likely be the most adopted despite its relative youth. Can I get a whoop-whoop foooooorrrrrrr.....

Unity Application Block

First up you need to track down the download of the binaries. If StructureMap is a little modest with its download link, Unity can only be described as coy. Following the links you'll likely end up here. Install the msi, and add a reference to Microsoft.Practices.Unity.dll.

The container in Unity is called UnityContainer (ObjectFactory in StructureMap provides static methods that wrap the Container, but it's still there). Unity is a breeze to get started with. All we need to do is create the container in our service locator, and register the types.

public static class ServiceLocator
{
    private static IUnityContainer _container;
 
    static ServiceLocator()
    {
        _container = new UnityContainer();
        _container.RegisterType<ITagService, UniqueTagService>();
        _container.RegisterType<ITagData, TagDatabase>();
    }
 
    public static T GetInstance<T>()
    {
        return _container.Resolve<T>();
    }
}

F*ck me, that was easy. Finding the download took longer! So easy that I had to find a similar implementation in StructureMap...

public static class ServiceLocator
{
    private static Container _container;
    static ServiceLocator()
    {
        _container = new Container(x => 
        { 
            x.ForRequestedType<ITagService>().TheDefaultIsConcreteType<UniqueTagService>();
            x.ForRequestedType<ITagData>().TheDefaultIsConcreteType<TagDatabase>();
        });
    }
    public static T GetInstance<T>()
    {
        return _container.GetInstance<T>();
    }
}

Here we're accessing the container directly, configured through the constructor. A few more lines of code, but as simple. I'll likely stick to using registries, but options are useful. (Note this would have taken me longer to discover if not for Jeremy D. Miller's epic weekend series of posts documenting StructureMap 2.5, this one in particular.)

Wrapping up

Remember that the above is the simplest of uses for a IoC container, but already I hope the value is clear. Next time we'll look at some of the more advanced uses, and, since I've enjoyed my introduction to Unity, maybe even get to know Autofac a little better...

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , ,

C# | Design Patterns

Comments

Add comment


(Will show your Gravatar icon)  

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

About me...

I'm a passionate .NET developer, with C# my language of choice. I've been at it for a number of years now, and enjoy that I'll never shake the feeling I'm just starting out.

I love software, and I love building it even more. I love knowing that my work facilitates others', and that one line of code at a time, we're increasing our capability.

More...



Page List