Chris Tavarez has provided a handy adapter (UnityServiceLocator) for using ServiceLocator to resolve types from a Unity container.  You can then use ServiceLocator.SetLocatorProvider() to register the UnityServiceLocator as the default provider for ServiceLocator. 

For this example, we will be using ServiceLocator and Unity to resolve the type IFoo to Foo using a singleton lifetime.  Then we will get two instances of IFoo and compare to ensure that they are the same object. 

Here are four different approaches to configuring ServiceLocator and Unity that I have found during my searches on the web:

1:

   1: static void Main(string[] args)
   2: {            
   3:     UnityServiceLocator locator = new UnityServiceLocator(ConfigureUnityContainer());
   4:     ServiceLocator.SetLocatorProvider(() => locator);
   5:  
   6:     var a = ServiceLocator.Current.GetInstance<IFoo>();
   7:     var b = ServiceLocator.Current.GetInstance<IFoo>();
   8:  
   9:     Console.WriteLine(a.Equals(b));            
  10: }
  11:  
  12: private static IUnityContainer ConfigureUnityContainer()
  13: {
  14:     UnityContainer container = new UnityContainer();
  15:     container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager());
  16:     return container;
  17: }

2:

   1: static void Main(string[] args)
   2: {      
   3:     ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(ConfigureUnityContainer()));
   4:  
   5:     var a = ServiceLocator.Current.GetInstance<IFoo>();
   6:     var b = ServiceLocator.Current.GetInstance<IFoo>();
   7:  
   8:     Console.WriteLine(a.Equals(b));            
   9: }
  10:  
  11: private static IUnityContainer ConfigureUnityContainer()
  12: {
  13:     UnityContainer container = new UnityContainer();
  14:     container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager());
  15:     return container;
  16: }

3:

   1: static void Main(string[] args)
   2: {
   3:     UnityContainer container = new UnityContainer();
   4:     container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager());
   5:  
   6:     ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));
   7:  
   8:     var a = ServiceLocator.Current.GetInstance<IFoo>();
   9:     var b = ServiceLocator.Current.GetInstance<IFoo>();
  10:  
  11:     Console.WriteLine(a.Equals(b));            
  12: }

4:

   1: static void Main(string[] args)
   2: {
   3:     UnityContainer container = new UnityContainer();
   4:     container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager());
   5:     UnityServiceLocator locator = new UnityServiceLocator(container);
   6:     
   7:     ServiceLocator.SetLocatorProvider(() => locator);
   8:  
   9:     var a = ServiceLocator.Current.GetInstance<IFoo>();
  10:     var b = ServiceLocator.Current.GetInstance<IFoo>();
  11:  
  12:     Console.WriteLine(a.Equals(b));            
  13: }

 

So these implementations seem to to do the same basic thing: register the UnityServiceLocator and use it to resolve types.  But…

howardpayne

Pop quiz:

Can you find the subtle differences and explain the problems that they can cause? 

Explanation:

Example #1:  This implementation works as expected.  The two instances (a and b) reference the same container controlled object.

Example #2:  This one is just wrong.  The two instances are not the same object, but two distinct objects.  Since the argument for the SetLocatorProvider() method is a delegate, each call to ServiceLocator.Current executes the delegate again, creating a new Unity container for every call.  This one also has the same side effect as #3.

Example #3:  This one gives the correct behavior with respect to instances a and b, but leads to a new UnityServiceLocator object being created for each ServiceLocator.Current call.  This could lead to a lot of objects just hanging around until the GC runs and reclaims the memory.

Example #4:  Works as expected.  Essentially the same as #1 but without wrapping the container creation in a method.

 

The two primary conclusions that I came to during this exercise are:

  1. Make sure that you understand the API and code that you are calling.  It may not always be black and white.  As in example #2 above, forgetting that this is a delegate can lead to the wrong behavior.
  2. Don’t rely blindly on example code from the internet.  Some of the code that I have posted is probably error prone.  Sample code is just that: a sample.