1

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?

Narayana
  • 2,654
  • 3
  • 32
  • 32
  • How and when do you need to choose/switch between the ICache implementations? Is this based on a web.config setting? Based on some program logic? – Steven Jan 06 '14 at 14:13
  • @Steven Program logic - one in-process cache (like Level 1), and one out-of-process cache (Level 2). But hey, even if I have only one type of cache (most likely), I want to simply use it in different places. I don't want to pass ICache through constructor in all places that I want to use caching. – Narayana Jan 06 '14 at 16:43
  • Why don't you want to use constructor injection? If you need to inject it in many places you are probably violating the Single Responsibility Principle. Caching is a cross cutting concern, best added using interception or decoration. – Steven Jan 06 '14 at 16:52

1 Answers1

2

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.

David
  • 3,736
  • 8
  • 33
  • 52
  • Thanks, this helped. Though I could not use the constructor injection because I was using Cache through PostSharp AOP. http://codereview.stackexchange.com/questions/20341/inject-dependency-into-postsharp-aspect helped me to overcome that issue. – Narayana Jan 08 '14 at 07:28