Skip to main content

This is only really applicable to non-web farm solutions as the data will be stored in process per IIS instance. If you want a distributed solution then look to pay big(ger) bucks or if you are hosting your site in Windows Azure then AppFabric Caching is the go and very reasonably priced. With that disclaimer aside though this works nicely for any single server solution and will cache any type of data.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Caching;

// -----------------------------------------------------------------------------
// DataCache: A simple (but effective) caching class
//
// I have been using this code for a while now and thought I would post it out
// to the community as a simple C# DataCache class that can be re-used.
//
// This is only really applicable to non-web farm solutions as the data will be
// stored in process per IIS instance. If you want a distributed solution then
// look to pay big(ger) bucks or if you are hosting your site in Windows Azure
// then AppFabric Caching is the go and very reasonably priced.
//
// With that disclaimer aside though this works nicely for any single server
// solution and will cache any type of data.
//
// I chose to have a DataCacheItem enum for each project I use this on, which is
// one of the parameters to the Insert, Get, Contains and Remove methods but you
// could always change to a string if you like. I prefer the strongly typed
// approach as it saves on typing errors.
//
// Usage is pretty darn simple and there is one overload for each method which
// takes a subKey of type int. This is a bit of a throw back from the first
// project I used it on but subKey always seems to be an ‘int’ for me so I have
// just left it as is. Again, feel free to change this to a more generic type if
// you want to improve the code.
//
// At the end of the code listing is some sample code of how to use the class.
// In this case I have a Home Controller which returns a Home Model. The model
// data rarely changes so is cached for a period of time and returned from the
// cache when available, which in my case will be for 15 minutes. The
// LoadHomeModel() method is a helper function which does all the hard work of
// loading the model.
//
// Hope you find the code useful and if you have any ideas for improvement,
// aside from making the key and subKey more generic, please drop me a line.
//
// If you spot any problems with this implementation I would also love to hear
// from you.
//
// Author: James Coenen-Eyre
// http://zurb.com/forrst/posts/DataCache_T_A_simple_but_effective_caching_c-w4G
// -----------------------------------------------------------------------------

namespace BondiGeek.Code
{
    public enum DataCacheItem
    {
        // These are specific to my implementation.
        // See description below
        LastTweet,
        WeatherReport,
        Toolbox,
        Work,
        Home,
        Blog
    }

    /// <summary>
    /// Library used for arbitrary caching of objects.
    /// </summary>
    public class DataCache
    {
        public static void Insert<T>(DataCacheItem key, T value)
        {
            lock (MemoryCache.Default)
            {
                MemoryCache.Default.Remove(key.ToString());
                DateTimeOffset expires = new DateTimeOffset(DateTime.Now.AddMinutes(Properties.Settings.Default.CacheDurationInMinutes));
                MemoryCache.Default.Add(key.ToString(), value, expires);
            }
        }

        public static void Insert<T>(DataCacheItem key, int subKey, T value)
        {
            lock (MemoryCache.Default)
            {
                MemoryCache.Default.Remove(string.Format("{0}-{1}", key.ToString(), subKey));
                DateTimeOffset expires = new DateTimeOffset(DateTime.Now.AddMinutes(Properties.Settings.Default.CacheDurationInMinutes));
                MemoryCache.Default.Add(string.Format("{0}-{1}", key.ToString(), subKey), value, expires);
            }
        }

        public static T Get<T>(DataCacheItem key)
        {
            if (MemoryCache.Default.Contains(key.ToString()))
            {
                return (T)MemoryCache.Default.Get(key.ToString());
            }
            else
            {
                return default(T);
            }
        }

        public static T Get<T>(DataCacheItem key, int subKey)
        {
            if (MemoryCache.Default.Contains(string.Format("{0}-{1}", key.ToString(), subKey)))
            {
                return (T)MemoryCache.Default.Get(string.Format("{0}-{1}", key.ToString(), subKey));
            }
            else
            {
                return default(T);
            }
        }

        public static bool Contains(DataCacheItem key)
        {
            return MemoryCache.Default.Contains(key.ToString());
        }

        public static bool Contains(DataCacheItem key, int subKey)
        {
            return MemoryCache.Default.Contains(string.Format("{0}-{1}", key.ToString(), subKey));
        }

        public static void Remove(DataCacheItem key)
        {
            MemoryCache.Default.Remove(key.ToString());
        }

        public static void Remove(DataCacheItem key, int subKey)
        {
            MemoryCache.Default.Remove(string.Format("{0}-{1}", key.ToString(), subKey));
        }
    }
}


//
// Usage sample within an MVC Controller
public ActionResult Index()
{
    // Get the data from the cache if available
    if (!DataCache.Contains(DataCacheItem.Home))
    {
        DataCache.Insert<HomeModel>(DataCacheItem.Home, LoadHomeModel());
    }

    return View(DataCache.Get<HomeModel>(DataCacheItem.Home));
}