Handy .Net CacheUtil

Found this handly little .Net cache util that I created once and realized it’s quite nice. It uses generics and Func delegates to solve common caching needs nicely.

Instead of writing lots of code to check if a cache key exists, create it, add to cache and so on, you basically use one line:

CacheUtil.GetOrCreate<MyType>("MyUniqueKey", FuncThatCreatesMyType, 30, myCacheLockObject);

Here’s the code:

using System;
using System.Web;

namespace MyNamespace
{
    public class CacheUtil
    {
        /// <summary>
        /// Try to get item from cache, create and cache using supplied Func delegate if it doesn't exist
        /// </summary>
        /// <typeparam name="T">The type of the object to get/create/cache</typeparam>
        /// <param name="cacheKey">The unique cache key</param>
        /// <param name="createMethod">The method to call to creating the object to cache</param>
        /// <param name="minutes">Amount of minutes to cache</param>
        /// <param name="lockObject">A static object to lock to prevent multiple threads from cacheing at the same time</param>
        /// <returns></returns>
        public static T GetOrCreate<T>(string cacheKey, Func<T> createMethod, int minutes, object lockObject)
        {
            var value = Get<T>(cacheKey);
            if (value == null)
            {
                lock (lockObject)
                {
                    value = Get<T>(cacheKey);
                    if (value == null)
                    {
                        value = createMethod();
                        if (value != null)
                        {
                            Cache<T>(cacheKey, value, minutes, lockObject);
                        }
                    }
                }
            }
            if (value != null)
            {
                return (T)value;
            }
            return default(T);
        }

        private static T Get<T>(string cacheKey)
        {
            if (HttpRuntime.Cache[cacheKey] != null)
            {
                return (T)HttpRuntime.Cache[cacheKey];
            }
            return default(T);
        }

        private static void Cache<T>(string cacheKey, T obj, int minutes, object lockObject)
        {
            lock (lockObject)
            {
                var item = Get<T>(cacheKey);
                if (item == null)
                {
                    HttpRuntime.Cache.Insert(cacheKey, obj, null, DateTime.Now.AddMinutes(minutes), System.Web.Caching.Cache.NoSlidingExpiration);
                }
            }
        }

        public static void Clear(string cacheKey)
        {
            HttpRuntime.Cache.Remove(cacheKey);
        }
    }
}

Example of how to use it:

using System;
using System.Web;

namespace MyNamespace
{
    public class MyClass
    {
        private static object cacheLockNewsArticles = new object();

        public List<NewsArticle> GetNewsArticles()
        {
            return CacheUtil.GetOrCreate<List<NewsArticle>>("MyNewsArticleCache", FetchNewsArticles, 30, cacheLockNewsArticles);
        }

        private List<NewsArticle> FetchNewsArticles()
        {
			//Return a List of NewsArticle...
        }
    }
}

The lockObject should be a static member in the calling class. The purpose of this is to prevent multiple web visitors/callers/threads to set the cache if it’s empty. The first visitor locks the static variable, other visitors wait while the first visitor executes the create method and populates the cache.

Comments and improvements appreciated.