C# – Container, Services and unity

A note of word on the container and Services.

the UnityContainer is a general Dependency Injection containers, often referred to as just “container”, are used to satisfy dependencies components, satisfing these dependencies typically involves registration and resolution.

The Composite Application Library provides support for the Unity Application Block (Unity) container, but it is not container-specific.

Because the library accesses the container through the IServiceLocator interface, the container can be replaced. To do this, your container must implement the IServiceLocator interface.

The composite Application library provides the UnityServiceLocatorAdatpr, the UnityServiceLocatorAdatper is an IUnityContianer adapter for the IServiceLocator interfaces. The UnityServiceLocatorAdapter is mapped to the IServiceLocator interface and the mapping is registered in the UnityBootstrapper class.

UnityServiceLocatorAdatper

As we have seen above, you can replace the UnityContinaer with some other containers, but the Composite Application Libraries uses the IServiceLocator to access the Container.

Normally if you replace the UnityContainer, you will need as well to write your ServiceLocatorAdapter, which is used to adapt the unity container or any other container to the Common Service Locator interface.

The typical implemenation of the UnityServiceLocatordapter has the followng code.

public class UnityServiceLocatorAdapter : ServiceLocatorImplBase
{
    private readonly IUnityContainer _unityContainer;

    public UnityServiceLocatorAdapter(IUnityContainer unityContainer)
    {
        _unityContainer = unityContainer;
    }

    protected override object DoGetInstance(Type serviceType, string key)
    {
        return _unityContainer.Resolve(serviceType, key);
    }

    protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
    {
        return _unityContainer.ResolveAll(serviceType);
    }
}

Basically there is a ServiceLocatorImplBase class provides standard implemenation of various methods on the IServiceLocator..

Here, the method is directly directed to the UnityContainer itself.

ServiceLocator and Unity – Becareful

However, there are some erroir prone use of the UnitContainer and the Service. Below shows four different way to configure ServiceLocator and Unity, some of which is less effecient, while some are totally wrong.

using System;
using Microsoft.Practices.ServiceLocation; // - ServiceLocator
using Microsoft.Practices.Unity; // - UnityServiceLocator

namespace ConfigureContainersAndServices
{
    class Program
    {

        static void Main(string[] args)
        {
            ConfigureViaUnityServiceLocator(args);
            //ConfigureViaUnityServiceLocator_EachResolveCreateNewContainer(args);
            //ConfigureViaUnityServiceLocator_EeachResolveCreateNewServiceLocator_SharedContainer(args);
            //ConfigureViaUnityServiceLocator_SharedContainer_SharedServiceLocator(args);
        }

        interface IFoo
        {
        }

        class Foo : IFoo
        {
        }

        // Configure Container and Services
        // 1. UnityServiceLocator
        static void ConfigureViaUnityServiceLocator(string[] args)
        {
            UnityServiceLocator locator = new UnityServiceLocator(ConfigureUnityContainer());
            ServiceLocator.SetLocatorProvider(() => locator);

            var a = ServiceLocator.Current.GetInstance < IFoo>();
            var b = ServiceLocator.Current.GetInstance<IFoo>();

            Console.WriteLine(a.Equals(b));
        }


        private static IUnityContainer ConfigureUnityContainer()
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager());
            return container;
        }


        // 2. a small variante of 1 - which has wrong result
        static void ConfigureViaUnityServiceLocator_EachResolveCreateNewContainer(string[] args)
        {
            ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(ConfigureUnityContainer()));

            var a = ServiceLocator.Current.GetInstance<IFoo>();
            var b = ServiceLocator.Current.GetInstance<IFoo>();

            Console.WriteLine(a.Equals(b));
        }


        // 3.a shared UnityContainer, but each time a new ServiceLocator object is created. 
        static void ConfigureViaUnityServiceLocator_EeachResolveCreateNewServiceLocator_SharedContainer(string[] args)
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager());

            ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));

            var a = ServiceLocator.Current.GetInstance<IFoo>();
            var b = ServiceLocator.Current.GetInstance<IFoo>();
            Console.WriteLine(a.Equals(b));
        }


        // 4. shared UnityContainer and the Shared ServiceLocator object
        static void ConfigureViaUnityServiceLocator_SharedContainer_SharedServiceLocator(string[] args)
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<IFoo, Foo>(new ContainerControlledLifetimeManager());

            var locator = new UnityServiceLocator(container);
            ServiceLocator.SetLocatorProvider(() => locator);

            var a = ServiceLocator.Current.GetInstance<IFoo>();
            var b = ServiceLocator.Current.GetInstance<IFoo>();
            Console.WriteLine(a.Equals(b));
        }

    }
}

I will be pasting the content of the explanation on the directly from the
ServiceLocator and Unity – Be Carefulbelow.

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.

And the experience that we gain is

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

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.

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.

Service Locator is an Anti-Pattern

Mark Seeman published a article denounce that Service Locator is an anti-pattern. more shall be coming to this topic.

References

Container and Services
ServiceLocator and Unity – Be Careful
CommonServiceLocator

Upgrading from the Composite Application Guidance for wPF 1.0
Service Locator is an Anti-Pattern

Similar Posts: