Just Sayin’ More Words

About This Post

Pluggable ASP.NET CacheManager

I wanted a single, common method for caching items for either the length of a request (in HttpContext.Current.Items) or longer (in HttpContext.Current.Cache). Here’s what I came up with.

There’s three common operations I use for caching: storing an item, removing an item and retrieving an item. I started by defining these methods in an interface:

public interface ICacheProvider
{
    void Store(string key, object data);
    void Destroy(string key);
    T Get<T>(string key);
}

Next up was my CacheManager class. I use this as a common interface to whatever ICacheProvider I want to use in each situation. Whenever you instantiate a CacheManager, you have to specify which provider you want to use, so I put that in the constructor. Then I implemented each of the common methods.

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);
    }
}

Right now, I only ever store cached items in two places: HttpContext.Current.Items for items that only need to live as long as a single request and HttpContext.Current.Cache for items that I need to live across requests (like a dynamically-generated CSS style sheet). So I wrote a ICacheProvider for each of these situations:

public class RequestProvider : ICacheProvider
{
    public void Store(string key, object data)
    {
        HttpContext.Current.Items.Add(key, data);
    }

    public void Destroy(string key)
    {
        HttpContext.Current.Items.Remove(key);
    }

    public T Get<T>(string key)
    {
        T item = default(T);
        if (HttpContext.Current.Items[key] != null)
        {
            item = (T)HttpContext.Current.Items[key];
        }
        return item;
    }
}

public class ShortTermProvider : ICacheProvider
{
    public void Store(string key, object data)
    {
        HttpContext.Current.Cache.Insert(key, data);
    }

    public void Destroy(string key)
    {
        HttpContext.Current.Cache.Remove(key);
    }

    public T Get<T>(string key)
    {
        T item = default(T);
        if (HttpContext.Current.Cache[key] != null)
        {
            item = (T)HttpContext.Current.Cache[key];
        }
        return item;
    }
}

For the ShortTermProvider you can specify additional options like absolute or sliding expirations using one of the other overloads on the Insert method.

Now I can easily and succinctly cache items in the desired location:

CacheManager cache = new CacheManager(new ShortTermProvider());
cache.Store("foo", "any-object-here");
string result = cache.Get<string>("foo");
cache.Destroy("foo");

Woot! In the future, if I ever need to implement memcached or Velocity, I can just write a new provider and plug it in.

kick it on DotNetKicks.com

Viewing 24 Comments