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.