Dependency Injection with Service Locators
To completely eliminate the need for the presenter to be aware of which implementation of IEmployeeTask it should use, you must add a new element into the mix. In the realm of dependency injection, a service locator is simply an object that knows how to retrieve dependencies for other objects. In this scenario, it would be the role of the service locator to find an implementation of IEmployeeTask that the presenter can work with. All of you who have been reading along probably know the answer to the question, "Does this mean that my presenter will now have a dependency on this service locator?" Absolutely. Then you might ask, "Does this mean I should start changing the constructor of my presenter to also allow it to accept a service locator?" You could do that. Unfortunately, if other classes down the road want to utilize the services of the locator to resolve their dependencies, they too would require a constructor that allowed them to accept an interface to the service locator. This seems like a little too intrusive to the architecture and more work than is necessary.
The solution I am going to propose is one that you can use immediately if you want to start utilizing service locators in your own projects. It is also a solution that can scale when you start using full-blown dependency injection frameworks like Windsor Castle, a popular, open-source dependency injection framework. I am first going to create an interface for the service locator:
public interface IDependencyResolver :
The preceding code uses generic methods to avoid the need to cast when invoking the locator from client methods. I stated that I want existing classes to be able to consume the functionality provided by the service locator without a need to have an explicit parameter dependency on it. To accomplish this I will use a static class that will delegate all of its calls to any particular implementation of the service locator interface:
public static class DependencyResolver
private static IDependencyResolver
public static void RegisterResolver(
DependencyResolver.resolver = resolver;
public static T GetImplementationOf<T>()
Notice that the DependencyResolver class has a method called RegisterResolver
which is passed an implementation of IDependencyResolver that it can forward its calls onto. What does this translate to from the perspective of the presenter? Instead of it needing to have knowledge of the EmployeeTask implementation of IEmployeeTask, it can now use the DependencyResolver class to locate an implementation of IEmployeeTask. This changes the constructors in EmployeePresenter from this:
Notice that I am still making use of the greedy constructor that requires everything that the presenter requires. I can use this constructor from a testing perspective to verify the behavior of the presenter. In the constructor that the web page uses, the presenter uses the DependencyResolver and asks it to retrieve an implementation of an IEmployeeTask. Now, nothing in the presenter couples it to the EmployeeTask component!
I chose to couple the presenter to the service locator by using the static DependencyResolver class. Someone out there right now is screaming, "static classes are evil!" In addition, lots of people scream, "singletons are evil." In either case, they are not evil, as long as they allow for testability, which is typically not easy to do with traditional singleton or static class implementations. This scenario makes testability easy because the DependencyResolver static class does nothing more than delegate its work to an IDependencyResolver implementation (which you can easily fake at test time).
The advantage of using the interface (IDependencyResolver) is that when I am first starting down the service locator route, I may be content with creating my own service locator that gets configured at application startup. Listing 5
shows the code for such a locator. Here's an example that configures such a locator in a class invoked at application startup:
public class ApplicationStartupTask
public static void Initialize()
IDependencyResolver resolver = new
Notice that I explicitly tell the service locator when asked for implementations of IEmployeeTask to return the EmployeeTask object. This particular implementation also enforces the EmployeeTask to be a singleton in this application, even though it is not explicitly marked as a singleton. The final step registers the service locator with the DependencyResolver so that all clients can access its functionality.
If you want more functionality out of your service locator you may not want to code it yourself. By using the IDependencyResolver interface, you can easily switch to an implementation that leverages already existing dependency injection frameworks. Listing 6
shows an example of an IDependencyResolver implementation coded to work with Windsor Castle.
The value of coding to interfaces means that when (and if) I switch to Windsor (or another dependency injection framework), very little of my client code should change. In fact, the only change required to use Windsor is to change the ApplicationStartupTask class as follows:
public class ApplicationStartupTask
private static readonly string
public static void Initialize()
IWindsorContainer container = new
The advantage of using a full-featured framework such as Windsor is that there is no longer any code (not even in ApplicationStartUp
) tied to particular implementations of dependencies. Objects that need dependencies can still ask the DependencyResolver class to retrieve them and the DependencyResolver will use whatever implementation of IDependencyResolver was provided to it to satisfy the request.
In the downloadable source code accompanying this article
, you can see how I configure the Windsor container using Binsor, a great tool for configuring Windsor without XML files. Ayende Rahien developed Binsor and it allows me to configure dependencies using configurations stored outside of the application.
I have covered a lot of ground in this article. I started with a single-tiered application that breaks many of the best practices that many of you are already well aware of. I introduced a layered architecture and some refactoring techniques that drove me to use the dependency inversion principle. You can see the benefit of coding to abstractions vs. implementations. To top it off, I introduced the concepts of dependency injection and service locators as tools to help you realize the benefit of coding to abstractions.
You now have another arsenal of tips and techniques that you can start applying to realize more loosely coupled solutions in your application architectures.