Critique: Pluggable ASP.NET CacheManager

Today as I was perusing DotNetKicks I ran across this post by John Sheehan. The post goes over creating a simple CacheManager that allows extensibility through interfaces. The basis of his class is dervived off the usage of.

public class CacheManager
{
    protected ICacheProvider _repository;
    public CacheManager(ICacheProvider repository)
    {
        _repository = repository;
    }

    public void Store(string key, object data)
    {
        _repository.Store(key, data);
    }

    public void Destroy(string key)
    {
        _repository.Destroy(key);
    }

    public T Get<T>(string key)
    {
        return _repository.Get<T>(key);
    }
}

You can view the full source with the implemenation of the interfaces and the declaration of the ICacheProvider interface over at his blog at Pluggable ASP.NET CacheManager.

Reading this post and one of the comments on his blog made me follow up in his comment stream, I felt like posting it here as it may benefit some of you also. Firstly I had to acknowledge the fact that Enterprise Library exists and contains it’s own Caching Application Block. Which also handles the concrete usages of the CacheProvider’s through a Factory implementation on the manager instead of concrete usage of the manager.

One of the posters on his blog asked the question “What’s the point in using CacheManager instead of just using the ICacheProvider instances?” This triggered my response on the elegance of this design John choose to follow for loosely coupling his code rather than direct coupling.

With your question if you implemented the caching solution using only the specific classes if you ever decided you wanted to change your caching backing store from HttpRuntime.Cache (note: John, you should reference the cache as HttpRuntime.Cache instead of Httpcontext.Current.Cache, calling the context just causes extra processing to just resolve to HttpRuntime.Cache) to a sql data store or to a memory caching solution like memcache or velocity you will now have to go into you code and change every single usage of RequestProvider to use MemCacheProvider or whatever other implementation you wish to use.

With a loosely coupled implementation that John created here, if you ever wish to switch from one provider to another you only ever need to change where it instantiates CacheManger to use the new provider instead. This brings me to my point about Enterprise Library’s CacheManager having a factory method for creating the caching providers usage, this will allow you to only need to declare the CacheProviders once in your code and no matter how many times you change the concrete implmentation of ICacheProvider you will only ever need to change 1 line of code in the entirety of your project which is a great thing indeed.

This idea of creating shared services that you can plug and play based off of interfaces is the basis of the idea of “Inversion of Control” or IoC that creates very robust and completely decoupled projects. Some of the most well known IoC frameworks are Microsoft’s Unity, Spring.NET, Castle Windsor, Ninject, StructureMap to name a few there are quite a bit of frameworks out there for IoC. Creating loosely coupled code is definitely getting to the point where it is mandatory for a project to be a well made solution.

It’s always a good day when I have the chance to discuss genericism, interfaces, loose coupling and inversion of control.

BloggingContext.ApplicationInstance.CompleteRequest();

7 thoughts on “Critique: Pluggable ASP.NET CacheManager

  1. I’m glad to hear from you John, it’s always refreshing to see other developers write elegant and simple code because that’s what is maintainable and when you look at it 6 months from now you still know exactly what it does.

  2. My point was the unneeded CacheManager class, what is the difference between:

    ICacheProvider cache = new ShortTermProvider();

    or

    CacheManager cache = new CacheManager(new ShortTermProvider());

  3. Steve,

    This goes back to my point if you skip the Manager wrapper class and go straight for ICacheProvider cache = new ShortTermProvider(); Should you later decide to make a different class say CloudPersistenceProvider() you will then have to change every single usage of

    ICacheProvider cache = new ShortTermProvider();

    to be

    ICacheProvider cache = new CloudPersistenceProvider();

    With the wrapper class you will only need to change each usage of CacheManager cache = new CacheManager(new ShortTermProvider()); In the implementation as it stands you will need to declare a manager in every single file to use it which is why I brought up the Enterprise Library implementation that uses a Singleton Factory to spawn every instance of ICacheProvider.

    The other great usage of a class like CacheManager is that you could adept it to use dependency injection in the constructor and have it use a static copy of the ShortTermProvider instead of having to reinitialize the class every single time.

    I understand the manager wrapper class can seem like just wasted lines of code but it really is a good implementation for this type of solution as it offers much more flexibility than if you deal with hardcoded dependencies to the classes that implement ICacheProvider.

    Did this answer your question clearer?

  4. new ShortTermProvider(); or new CacheManager(new ShortTermProvider()); is just as strongly coupled…

    It adds no extra functionality, it adds an extra layer of method calls.

    My point is everywhere you declare the CacheManager field/variable you could just declare a ICacheProvider, which can also be used by any DI/IoC framework.

  5. At this point it would depend what type of functionality you would want handled by the CacheManager and what you would want handled by the individual providers. If you have associative operations such as validation on objects that are inserted into the cache.

    At this point to shift the validation aspect into the Provider to handle it also, in my opinion would be a conflict to separation of intention and will muddy the intent of the CacheProviders.

    If the CacheManger will absolutely never have any type of logic to wrap around any methods interacting with the Providers, then yes I agree you can just remove the Manager and directly use the Providers. Personally I would still keep the Manager as a wrapper because it offers the flexibility of adding in those associative operations without changing the framework whereas using the Providers directly you would then be faced the choice of either having to combine the intention of the providers and directly implement the operations there or you would need to architect in the Manager type class anyway.

    I feel adding this extra layer is good practice as it promotes separation of intention between code, especially if you want to keep the ICacheProviders in a different assembly, the core project will not need to maintain any dependency on that assembly and only the assembly with CacheManager.

    If the manager works mostly as a pass through it is up to personal choice if you feel it should be there or not, I tend to side on design first, refactor later. If you see after implementation that is really is just adding a layer and not being used it’s always easier to refactor out a layer than it is to refactor IN a layer.

    As always there is no clear answer to what is good design, because design in itself is very subjective. The most important part of design is to trigger the thought process and communicate ideas and use what makes sense for the situation. I always believe an indepth design discussion is never a waste of time even if the end resolution is to not make any changes as it always brings clearer understanding and new thoughts to the table.

  6. The idea behind a Manager is for ‘managing’ objects and in this case ICacheProviders. Normally you would use something such as CacheManager cManager = CacheManager.GetDefaultManager() instead of instantiating the type of ICacheProvider you wish to use in the case of new CacheManager(new ShortTermCacheProvider()).

    By abstracting the providers and using a factory it simplifies the process of managing the cache. If you want to use MemCached, implement an ICacheProvider and set it via configuration files to set the default cache provider as memcached. If later on you wish to switch to Microsoft Velocity, implement the ICacheProvider and just change the configuration. The same with any other provider.

    In essence it provides an abstracted Cache Provider to work with and refraction so you can set the provider via configuration files (and simply doing the above two mentioned steps to switch to a different cache). See http://blogs.microsoft.co.il/blogs/gilf/ for Entity Framework Caching Application Block information. Reuse tested code! 🙂

Leave a comment