Humblecoder

Apprentice unit tester, expert rambler

Detangling Service Locator From Dependency Injection

with 5 comments

I’m sure like many exploring Dependency Injection (DI) for the first time the biggest problem I had, was how to rid the world of those pesky little new statements.  The first application I tried to use DI with in anger was DirLinker.  I had no prior knowledge of any of the DI frameworks and started looking at patterns that would help me remove all the new statements.  Unfortunately, I hit up on service locator and the rest is a mess history.  I ended up with code the looks like the following inside DirLinker:

IFile aFile = ClassFactory.CreateInstance<IFile>();
aFile.SetFile(file);

There is a couple of things that bother me about this.  First is the static, I’m not a fan of statics at all, infact, I hate them.  Next is the SetFile call, for any meaningful work to be done with this class you need to pass in a filename and it should be a constructor argument.  In all fairness the SetFile problem is more to do with the limitations of my roll your own DI framework than anything else.

In spite of my niggling doubts, it worked so I left it alone.  Fast forward to last week when I came across a blog post entitled Service Locator is an Anti-Pattern.  This confirmed my initial discomfort and highlighted a problem I hadn’t thought of, namely that the class doesn’t advertise its dependencies.  Very bad for reuse.

Factories

As the blog post suggests a better way of doing this would have been to use factories so lets go over a couple of examples on how this could be achieved. 

Virtual Instance Methods

This is a method I would use when trying to a create a seam in legacy code to inject a dependency for unit testing.  To do this you create a virtual method on the class that needs to create the object. In the unit test inherit from the class under test and override the factory method to return your mock or stub.  For example:

public class FileConsumer
{
    protected virtual IFile GetFile(String filename)
    {
        return new FileImp(filename);
    }

    public void DoSomething()
    {
        IFile fileA = GetFile("test.txt");
        IFile fileB = GetFile("test2.txt");
        //uses files
    }
}

[TestFixture]
public class FileConsumerTests : FileConsumer
{
    protected override IFile GetFile(string filename)
    {
        return new FileMock(filename);
    }

    [Test]
    public void DosomethingTest()
    {
        //Code to perform test
    }
}

This is good because it’s clear to any maintainer what the dependency is and where it is coming from. 

Abstraction Factory Pattern

This would loudly and proudly advertise the dependency on the ability to create IFile objects.  It works by creating a class with methods solely responsible for creating IFile objects and then taking this as dependency for your class.  For example:

public interface IFileFactory
{
    IFile CreateFile(String filename);
}

public class FileFactory : IFileFactory
{
    public IFile CreateFile(string filename)
    {
        return new FileImp(filename);
    }
}

public class FileConsumer
{
    IFileFactory _fileFactory;

    public FileConsumer(IFileFactory fileFactory)
    {

        _fileFactory = fileFactory;
    }

    public void DoSomething()
    {
        IFile fileA = _fileFactory.CreateFile("test.txt");
        IFile fileB = _fileFactory.CreateFile("test.txt");
        //uses files
    }
}

This is the pattern recommended by the blog post and it covers all the things I don’t like about Service Locator.  But I think we could take advantage of some of C#’s language features and the fact we are creating objects via a container to achieve something similar but with less code.

Delegate Factories

Before I go into this a little disclaimer, this is totally and utterly inspired by Autofac’s wonderful generated delegate factory functionality, you can read more about it here.

OK, honesty out of way lets look at what the container knows and what it does.  The DI container knows what Interfaces should map on to what concrete types and it has the ability to resolve constructor arguments for types that it knows about.  This is just a generic version of a factory so it makes sense to take advantage of it.

One way would be to use Func<TResult>() (and its friends).  If the class being constructed requires a constructor parameter of Func<TResult> where TResult is the required interface, the container could generate an appropriate delegate at runtime and pass it in.  For example:

   public class FileConsumer
   {
       Func<IFile> _fileFactory;

       public FileConsumer(Func<IFile> fileFactory)
       {

           _fileFactory = fileFactory;
       }

       public void DoSomething()
       {
           IFile fileA = _fileFactory();
           IFile fileB = _fileFactory();

           //uses fileA
       }
   }

This would require a slight modification to the container and could be extended by the use of Func<T, Tn, TResult>(T value, Tn valuen).  The container would match the parameters to a suitable constructor. 

This is quite a powerful and time saving concept but I don’t like the vagueness of Func<TResult>(), it’s not as expressive as it could be.  So the method I have chosen for DirLinker is to use strongly typed delegates and generate them at runtime from the container.   It works in the same manner only you declare the delegate up front and pass them in as an argument.  This, also, requires a bit of configuration but the pay off is worth it.  I have started work on the implementation for DirLinker so this example is taken directly from the unit tests and can be found here

interface ITestClassWithDelegateFactory { ITestClassFactory Factory { get; set; } }
delegate ITestClass ITestClassFactory();

class TestClassWithDelegateFactory : ITestClassWithDelegateFactory
{
     public ITestClassFactory Factory { get; set; }
     public TestClassWithDelegateFactory(ITestClassFactory delegateFactory)
     {
         Factory = delegateFactory;
     }
}

[Test]
public void ManufactureType_Type_delegate_factory_manufactures_correct_type()
{
	IClassFactory testClassFactory = new ClassFactory();

	testClassFactory.RegisterType<ITestClass, TestClass>()
                .WithFactory<ITestClassFactory>();

	testClassFactory.RegisterType<ITestClassWithDelegateFactory, TestClassWithDelegateFactory>();

 	ITestClassWithDelegateFactory manufacturedType =
			testClassFactory.ManufactureType<ITestClassWithDelegateFactory>();
	ITestClass instance = manufacturedType.Factory();

	Assert.IsInstanceOf(typeof(TestClass), instance);

}

Admittedly there is quite a lot going on here but the main points are we registered a type and factory in a strongly typed manner with the container.  Then pull it out and use it to create an instance of a different type.  I am going to cover this in quite some detail along with the how to create strongly typed delegates at runtime in my next post.

VN:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)

Written by Will

February 9th, 2010 at 7:42 am

Posted in .NET, C#, DirLinker, Unit testing

Tagged with , ,

5 Responses to 'Detangling Service Locator From Dependency Injection'

Subscribe to comments with RSS or TrackBack to 'Detangling Service Locator From Dependency Injection'.

  1. What’s wrong with just passing in IFileFactory to the constructor of FileConsumer?

    To me, that’s why constructor injection exists?

    Forgive me if I’m missing the point – feel free to tell me why constructor injection doesn’t cover the above scenario!

    VA:F [1.9.3_1094]
    Rating: 4.0/5 (1 vote cast)

    Rob Ashton

    9 Feb 10 at 09:28

  2. I don’t mind the passing of the factory at all and it is a lot clearer as to what is going on.

    My point was if we do this a lot we could end up writing a lot of boiler plate code when we could take advantage of the language to help us out and, ultimately, the less code the better :)

    VN:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)

    Will

    9 Feb 10 at 09:35

  3. Perhaps I’m being naive but this (for me) adds level complexity rather than make things clearer, certainly where you don’t already have a widely distributed codebase.
    Using DSL-based IoC tools I’ve found our configurations to be straight-forward/explicit and leverage the greatest amount of power & flexibility.
    Just my two-pennies worth :)

    VA:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)

    Ian

    9 Feb 10 at 09:56

  4. [...] This post was mentioned on Twitter by Graeme Foster, Will Charles. Will Charles said: blogged: Detangling Service Locator From Dependency Injection http://bit.ly/buVHMJ [...]

  5. [...] my previous post I talked about using the abstract factories pattern instead of the service locator pattern.  [...]

Leave a Reply

Get Adobe Flash playerPlugin by wpburn.com wordpress themes