Service locator

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

Problem

You have classes that have dependencies on services whose concrete type is specified at design time. In this example, ClassA has dependencies on ServiceA and ServiceB. Figure 1 illustrates this.

Figure 1 ClassA has dependencies on ServiceA and ServiceB

This situation has the following constraints:

  • To replace or update the dependencies, you must change your classes' source code.
  • The concrete implementation of the dependencies must be available at compile time.
  • Your classes are difficult to test in isolation because they have a direct reference to their dependencies. This means that these dependencies cannot be replaced with stubs or mocks.
  • Your classes contain repetitive code for creating, locating, and managing their dependencies.

Forces

Any of the following conditions justifies using the solution described in this pattern:

  • You want to decouple your classes from their dependencies so that these dependencies can be replaced or updated with minimal or no changes to your classes' source code.
  • You want to write classes that depend on classes whose concrete implementation is not known at compile time.
  • You want to be able to test your classes in isolation, without using the dependencies.
  • You want to decouple your classes from being responsible for locating and managing the lifetime of dependencies.

Solution

Create a service locator that contains references to the services and that encapsulates the logic to locate them. In your classes, use the service locator to obtain service instances. Figure 2 illustrates this.

Figure 2 ClassA uses the service locator to get an instance of ServiceA

The service locator does not instantiate the services. It provides a way to register services and it holds references to the services. After the service is registered, the service locator can find the service.

Note:

The service locator should provide a way to locate a service without specifying the concrete type. For example, it could use a string key or a service interface type. This enables easy replacement of the dependency concrete implementation without modifying your classes' source code.

Implementation with the Unity Application Block

The Service Locator pattern can be implemented in several ways. The Unity Application Block provides a container that can be used as a service locator. For more information about the Unity Application Block, see Unity Application Block.

Example

The following code, extracted from the NewsModule class of the Stock Trader Reference Implementation (this class is located at StockTraderRI.Modules.News\NewsModule.cs), shows how an instance that implements the INewsController interface is obtained using the service locator pattern. The variable _container holds an instance to a Unity container that has logic to locate a valid instance of the requested type.

C#

public void Initialize(){    RegisterViewsAndServices();    INewsController controller = _container.Resolve<INewsController>();    controller.Run();} 

Note that for testing purposes, you could configure the container to return a mock instance that implements the INewsController interface instead of the real implementation. This enables you to test the NewsModule class in isolation. The following code, extracted from the NewsModuleFixture test class (located at StockTraderRI.Modules.News.Tests\NewsModuleFixture.cs), shows how the NewsModule class can be tested in isolation using a mock instance for the INewsController interface.

C#

[TestMethod]public void InitCallsRunOnNewsController(){    MockUnityResolver container = new MockUnityResolver();    var controller = new MockNewsController();    container.Bag.Add(typeof(INewsController), controller);    var newsModule = new NewsModule(container);     newsModule.Initialize();     Assert.IsTrue(controller.RunCalled);} 

Liabilities

The Service Locator pattern has the following liabilities:

  • There are more solution elements to manage.
  • You have to write additional code to add service references to the locator before your objects use it.
  • Your classes have an extra dependency on the service locator.
  • The source code has added complexity; this makes the source code more difficult to understand.

Related Patterns

The following patterns are related to the Service Locator pattern:

  • Dependency Injection. The Dependency Injection pattern solves the same problems that the Service Locator pattern solves, but it uses a different approach.
  • Inversion of Control. The Service Locator pattern is a specialized version of the Inversion of Control pattern where the concern being inverted is the process of obtaining the needed dependency.