Simplify Your Caching By Using a Generic Method

I needed to add caching to my data access routines to improve the performance of commonly accessed data.  This is pretty straightforward:

  • Check to see if the cache entry already exists
  • If the cache entry does exist, return the cached value
  • If the cached entry doesn’t exist, fetch the data and add it to the cache.

The problem was, I had a lot of data access routines that I wanted to add caching to.  Adding the 4 or 5 lines of code needed to do this to each routine would be tedious, and all of the repetition would be messy.  I knew I had to centralize my caching functionality in one place.  Since my data access routines returned many different types, I decided to use a generic method to perform the caching.  Since the data validation routines essentially had to be wrapped by this function (so that it’s only run if the value doesn’t exist in the cache), I call it using a statement lambda.

Here’s what I came up with:
//I use ASP.Net's cache object.  I get a reference to it with System.Web.HttpRuntime.Cache
//as I won't always be using it in the context of ASP.Net
private static System.Web.Caching.Cache DataCache = System.Web.HttpRuntime.Cache;

public static T CacheFetch<T>(string key, Func<T> fetcher) where T:class
{
	//Don't bother with the caching if the key is null or blank
	if ((key ?? "").Length <= 0)
	{
		return fetcher();
	}

	T result = DataCache[key] as T;

	if (result == null)
	{
		result = fetcher();

		if (result == null)
		{
			DataCache.Remove(key);
		}
		else
		{
			DataCache[key] = result;
		}
	}

	return result;
}

And here’s some examples of how I used it:

Original data access routine:
public static IEnumerable<Trustee> GetTrustees(int infoReturnID)
{
	InfoReturnEntities context = new InfoReturnEntities(new Uri(Common.InfoReturnDataServiceURL));

	IEnumerable<Trustee> trustees = from trustee in context.Trustees
									where trustee.InfoReturnID == infoReturnID
									select trustee;

	return trustees;
}
Updated data access routine:
public static IEnumerable<Trustee> GetTrustees(int infoReturnID)
{
	return Common.CacheFetch<IEnumerable<Trustee>>("Trustees_" + infoReturnID.ToString(), () =>
	{
		InfoReturnEntities context = new InfoReturnEntities(new Uri(Common.InfoReturnDataServiceURL));

		IEnumerable<Trustee> trustees = from trustee in context.Trustees
										where trustee.InfoReturnID == infoReturnID
										select trustee;

		return trustees;
	});
}
And another example:
public static IEnumerable<RevenueRange> GetRevenueRanges()
{
	return Common.CacheFetch<IEnumerable<RevenueRange>>("RevenueRanges", () => {
		InfoReturnEntities context = new InfoReturnEntities(new Uri(Common.InfoReturnDataServiceURL));

		IEnumerable<RevenueRange> revenueRanges = from e in context.RevenueRanges
												  where e.RevenueRangeCD != "?"
												  orderby e.LowerLimit
												  select e;

		return revenueRanges;
	});
}

My method was inspired by this.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *