Question

I'm building an ASP.NET MVC app, and implementing Dependency Injection for the first time using Unity. For one particular interface, I've multiple types registered, like so:

container.RegisterType<ICache, AppfabricCache>("AppfabricCache", new ContainerControlledLifetimeManager());
container.RegisterType<ICache, MemoryCache>("MemoryCache", new ContainerControlledLifetimeManager());

I now need to make a decision on which one to use based on a CacheType enum.

I can implement it as follows, as is done in the Sixeyed.Caching project, but it makes you register types in different places. Also you now have a static wrapper around the container, which doesn't feel clean.

public static class Cache
{
    private static readonly IUnityContainer _container;
    static Cache()
    {
        _container = new UnityContainer();
        _container.RegisterType<ICache, MemoryCache>("MemoryCache", new ContainerControlledLifetimeManager());
    }

    public static ICache Get(CacheType cacheType)
    {
        ICache cache = new NullCache();
        switch(cacheType)
        {
            case CacheType.Memory:
                cache = _container.Resolve<ICache>("MemoryCache");
                break;
            ...
            ...
        }
    }   
}

How do I get hold of the container from other library projects in my application? Or rather, how do I do this kind of resolution from libraries? Or maybe I should not?

This blog post says it is not a good idea to have the container outside of the application entry point, which sounds correct. What is the correct way to do this?

Was it helpful?

Solution

As @ploeh suggests, the container shouldn't be known outside of the application root.
To get an implementation based on a runtime value, you should use a factory:

public class CacheFactory : ICacheFactory 
{
    private readonly IUnityContainer _container;

    public CacheFactory(IUnityContainer container)
    {
        if (container == null) 
            throw new ArgumentNullException("container");

        _container = container;
    }

    public ICache Get(CacheType cacheType)
    {
        // implementation as in your post
    }
}

public class SomethingUsingTheCache
{
    private readonly ICacheFactory _cacheFactory;

    public SomethingUsingTheCache(ICacheFactory cacheFactory)
    {
        if (cacheFactory == null) 
            throw new ArgumentNullException("cacheFactory");

        _cacheFactory = cacheFactory;
    }

    public void DoStuff()
    {
        // get from config or wherever
        CacheType cacheType = CacheType.Memory;

        ICache cache = _cacheFactory.Get(cacheType);
        // do something with cache 
    }
}

The factory is placed in the application root and any other class uses the factory and has no notion of the container.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top