Asp.net Cache Implementation with a Fallback Function

The power of caching in ASP.NET is exposed via the Cache object. Using the Cache object which is in the namespace System.Web.Caching, you can store any serializable data object, and control how that cache entry expires based on a combination of one or more dependencies.

My intention here is to create a class that manage all the cache of the application, this implementation will have a fallback function that will allow us to run a function in order to get the data that we want to cache and then be cached.

First thing I will do is to create the class CacheItem that will contain all the additional properties that we want to store with the actual value.

public class CacheItem
    {
        public string Key { get; set; }

        public object Value { get; set; }

        public DateTime? AddedToCacheOn { get; internal set; }

        public TimeSpan CacheDuration { get; set; }
    }

Next step is to create an interface with all the methods that we need to implement. As you have probably noticed I like to programming against interfaces.

public interface ICacheManager
    {
        void RemoveAll();

        void AddOrUpdate(CacheItem cacheItem);

        void Remove(CacheItem cacheItem);

        void Remove(string key);

        T Get<T>(string key) where T : class;

        T GetWithFallback<T>(string key, int cacheDurationMinutes, Func<T>     fallbackQueryFunc) where T : class;
    }

And then we just simply need to create the concrete class that implements the ICacheManager.

public class AspNetCacheManager : ICacheManager
    {
        private Cache cache;

        public AspNetCacheManager()
        {
            this.cache = HttpRuntime.Cache;
        }

        public void RemoveAll()
        {
            var enumerator = HttpRuntime.Cache.GetEnumerator();
            while (enumerator.MoveNext())
            {
                this.cache.Remove((string)enumerator.Key);
            }
        }

        public void AddOrUpdate(CacheItem cacheItem)
        {
            if (cacheItem.Key == null || cacheItem.Value == null)
                return;

            cacheItem.AddedToCacheOn = DateTime.Now;
            this.cache.Insert(cacheItem.Key, cacheItem.Value, (CacheDependency)null, DateTime.UtcNow.AddMinutes(cacheItem.CacheDuration.TotalMinutes), Cache.NoSlidingExpiration);
        }

        public void Remove(CacheItem cacheItem)
        {
            this.cache.Remove(cacheItem.Key);
        }

        public void Remove(string key)
        {
            this.cache.Remove(key);
        }

        public T Get<T>(string key) where T : class
        {
            return  this.cache.Get(key) as T;
        }

        public T GetWithFallback<T>(string key, int cacheDurationMinutes, Func<T> fallbackQueryFunc) where T : class
        {
            T obj1 = this.Get<T>(key);

            if ((object)obj1 != null)
                return obj1;

            T obj2 = fallbackQueryFunc();

            this.AddOrUpdate(new CacheItem()
            {
                CacheDuration = new TimeSpan(0, cacheDurationMinutes, 0),
                Key = key,
                Value = (object)obj2
            });

            return obj2;
        }

As you can see the Cache object expose some methods like Insert, Remove, Get, etc. This class is just a wrapper that add additional functionality and more information to it.

The method called GetWithFallback is the interesting one, it is a Generic method that allow us to run a expression if the cache item hasn’t been cached yet. It first try to get the item from the cache by key if it is not exist, the function expression is executed and the result is stored in the cache with the key provided.

This is an example is how to use this class

[TestMethod]
        public void GetWithFallback_ShouldNotCallTheFallbackFunctionToGetTheValue_WhenTheValueIsStoredInTheCache()
        {
            //Arrange
            var cacheItem = new CacheItem()
            {
                CacheDuration = new TimeSpan(0, 0, 0, 120),
                Key = "testKey",
                Value = "12345"
            };

            _sut.AddOrUpdate(cacheItem);

            //Act
            _sut.GetWithFallback("testKey", 2, () => GetFakeValue());

            //Assert
            Assert.AreEqual("12345", _sut.Get<string>("testKey"));
        }

        private string GetFakeValue()
        {
            return "Fake Value";
        }

You can find the code of this article here

Advertisements
This entry was posted in ASP.NET and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s