Common Service Locator

One of the nice things about Dependency Injection is that it can really help write a more flexible, modular application.  These days, it seems that there is no shortage of choice in the .NET community when it comes to IoC frameworks:

Ironically, when you first start using an IoC framework, you might find that in trying to make a loosely-coupled, modular, application you end up shackling yourself to the framework you’re using for IoC.

For example, you start off using your own homegrown IoC framework, and then decide at some point in the future to use a different framework, like say StructureMap.  Going through your codebase to make these changes can be quite the exercise in pain.

There are a couple of ways to isolate yourself from this kind of situation.  I won’t get into all of them but instead will focus on the Common Service Locator. What is Common Service Locator?  Well, allow me to cut and paste some text from the web site:

"The Common Service Locator library contains a shared interface for service location which application and framework developers can reference. The library provides an abstraction over IoC containers and service locators. Using the library allows an application to indirectly access the capabilities without relying on hard references. The hope is that using this library, third-party applications and frameworks can begin to leverage IoC/Service Location without tying themselves down to a specific implementation.

Blah blah blah – so what does all that mean?  Well, in my own words, CSL is basically a wrapper around your IoC container which separates how you  initialize/configure your IoC container from how you use it.  This separation allows you to use your IoC container without knowing anything about it.

This separation is achieved by use of adapters for the particular IoC container that you want to use.  These adapters are what do the dirty work of finding the service you need, in their own special way and totally transparent from your application code.  Currently, the Common Service Locator has adapters for StructureMap, Castle Windows, Unity, Spring.NET, and autofac.

Now, allow me an example of using the Common Service Locator with StructureMap. There is no special reason as to why StructureMap – it just happens to be what I find myself using these days.

Now, say I use the the following registry to configure StructureMap:

   1: public class DefaultStructureMapRegistry: Registry
   2: {
   3:     public DefaultStructureMapRegistry()
   4:     {
   5:         ForRequestedType<IDb4oConfiguration>()
   6:             .TheDefaultIsConcreteType<SimpleDb4oConfiguration>();
   7:     }
   8: }

In a nutshell this says that every time StructureMap is asked to provided an object of type IDb4oConfiguration, it should instantiate a SimpleDb4oConfiguration object and return that.  So, to get an instance of IDb4oConfiguration with StructureMap, I would do something like this:

   1: var db4oConfig = ObjectFactory.GetInstance<IDb4oConfiguration>();

Pretty simple, but it does kind of tightly couples me to StructureMap.  If I need/feel like/am forced at gunpoint to change my IoC container to something that is Not StructureMap, you can bet that there will be much wailing and gnashing of teeth on my part as I hunt through my code to make these changes.

Now enter the Common Service Locator.  First, let’s take a peek at some interfaces for CSL.  First an interface:

   1: namespace Microsoft.Practices.ServiceLocation
   2: {
   3:     public interface IServiceLocator : IServiceProvider
   4:     {
   5:         object GetInstance(Type serviceType);
   6:         object GetInstance(Type serviceType, string key);
   7:         IEnumerable<object> GetAllInstances(Type serviceType);
   8:         TService GetInstance<TService>();
   9:         TService GetInstance<TService>(string key);
  10:         IEnumerable<TService> GetAllInstances<TService>();
  11:     }
  12: }

The IServiceLocator is an interface that your application will use when it requests something from your IoC container.

Another thing that CSL provides is a static class that your application would use to use a current IServiceLocator to request services.  That static class looks something like:

   1: namespace Microsoft.Practices.ServiceLocation
   2: {
   3:     public static class ServiceLocator
   4:     {
   5:         public static IServiceLocator Current { get; }
   6:         public static void SetLocatorProvider(ServiceLocatorProvider newProvider) {};
   7:     }
   8: }

So, now lets see how we would request the default implementation of the IDb4oConfiguration service using CSL.  First, we would initialize CSL:

   1: var registry = new DefaultStructureMapRegistry();
   2: var container = new global::StructureMap.Container(registry);
   3: var smServiceLocator = new StructureMapServiceLocator(container);
   4: ServiceLocator.SetLocatorProvider(() => smServiceLocator );

What is going on here? Allow me to provide a quick line by line explanation:

Line 1 we instantiate a new StructureMap registry.  We then feed that registry to a StructureMap container in line 2.  With line 3, we see that StructureMap container is then fed to the StructureMapServiceLocator, which is the SM adapter for the Common Service Locator.  Finally, with line 4 we provide a lambda that CSL will use to fulfill future requests for services.

Now when our application wants to get an instance of IDb4oConfiguration it just politely asks CSL:

   1: var db4oConfig = ServiceLocator.Current.GetService<IDb4oConfiguration>();

Pretty simple and clean, eh?  Now, when radical group the Foundation for Unity as the Dominate IoC Container sneaks into your cube and forces you at the point of a nerf gun to switch to Unity, you can do so with minimal disruption to your application. With a properly layered application, it would be as simple as coding a new UnityConfiguration layer and then using that instead of your StructureMapConfiguration layer on application startup.

Now, granted this is pretty trivialized example.  There are other ways to solve this problem, but CSL does seem to take are of the grunt work for you so that you can just get going with things.