Enterprise Asp.Net MVC Part 8: Asp.Net cache before repository<!-- --> | <!-- -->Patrick Desjardins Blog
Patrick Desjardins Blog
Patrick Desjardins picture from a conference

Enterprise Asp.Net MVC Part 8: Asp.Net cache before repository

Posted on: February 27, 2014

At some point in the life of your software the performance can become an issue. If you have optimized your queries or your Entity Framework configuration, than the next step is to think about keeping some data in memory or in an external cache. This has the advantage to have the data already available.

First of all, we need to have some infrastructure classes and interface because we want to have something flexible and not tightly bound to Asp.Net since this will be used in the Data Access Layer.

1public interface ICacheConfiguration { bool IsActivate(); }
2``` The first interface configures the cache. So far, to keep it simple, only one property is set. It is about its activation. Caching system must always have a possibility to be desactivated. The reason is that if your data become not what you expect that you can turn off the cache and use the main persistence. If the problem is solved, than it means that the problem is the cache. Otherwise, the problem is with the persistence or the logic that use the data.
4 public interface ICacheProvider { void Set<T>(T objectToCache) where T : ICachableModel;
6void Set(string key, Object objectToCache);
8T Get<T>(T key) where T : ICachableModel;
10object Get(string key);
12object Delete(string key);
14T Delete<T>(T objectTodelete) where T : ICachableModel;
16bool IsInCache(string key);
18bool IsInCache<T>(T objectToVerify) where T : ICachableModel; }
19``` This second interface allows you to have something in front of the technology used. You can have a memory cache, an external caching system or to have an Azure cache behind this interface.
23 public interface ICachableModel { string GetCacheKey(); }

Most of the methods are defined twice. One use a string key, and the other use a ICachableModel. This interface allows to have the model class to have its logic to built its unique key.

1public class MemoryCache:ICacheProvider { private readonly ObjectCache cache; private readonly CacheItemPolicy defaultPolicy; private readonly ICacheConfiguration configuration;
3public MemoryCache(ICacheConfiguration configuration) { this.configuration = configuration; this.cache = new System.Runtime.Caching.MemoryCache(Constants.Configurations.CacheNameConfiguration); this.defaultPolicy = new CacheItemPolicy(); }
5public void Set<T>(T objectToCache) where T : ICachableModel { if (configuration.IsActivate()) { cache.Set(objectToCache.GetCacheKey(), objectToCache, defaultPolicy); } }
7public void Set(string key, object objectToCache) { if (configuration.IsActivate()) { cache.Set(key, objectToCache, defaultPolicy); } }
9public T Get<T>(T objectToCache) where T : ICachableModel
11{ if (configuration.IsActivate()) { return (T) cache.Get(objectToCache.GetCacheKey()); } else { return default(T); } }
13public object Get(string key) { if (configuration.IsActivate()) { return cache.Get(key); } else { return null; } }
15public object Delete(string key) { if (configuration.IsActivate()) { return cache.Remove(key); } else { return null; } }
17public T Delete<T>(T objectTodelete) where T : ICachableModel { if (configuration.IsActivate()) { return (T) cache.Remove(objectTodelete.GetCacheKey()); } else { return default(T); } }
19public bool IsInCache(string key) { if (configuration.IsActivate()) { return cache.Contains(key); } else { return false; } }
21public bool IsInCache<T>(T objectToVerify) where T : ICachableModel { if (configuration.IsActivate()) { return cache.Contains(objectToVerify.GetCacheKey()); } else { return false; } } }
22``` This implementation uses the System.Runtime.Caching as you can see, it also use the configuration to disable the cache. This way to proceed does not affect any of the caller code. In fact, all method return the default value when the cache does not find the value. This should tell to the called to continue with the default persistence strategy.
24The caller should be in the Services classes if you have followed previous post about Enterprise Asp.Net MVC application.
28 var cacheResult = (YouEntity)this.cache.Get("YouUniqueKey123"); if (cacheResult == null) { var repositoryResult = yourRepository.GetYourEntity(); this.cache.Set("YouUniqueKey123", repositoryResult); return repositoryResult; } else { return cacheResult; }

This create a simple architecture for caching. It has the flexibility to use the concrete cache you want and to have high cohesive classes. Configurations could have additional information about how many time the entity must stay in cache, the information about external cache like which IP or PORT to use for MemCached for example.

Series Articles

Article #1: Asp.Net MVC Enterprise Quality Web Application Article #2: Asp.Net MVC Enterprise Quality Web Application Model Article #3: Asp.Net MVC Enterprise Quality Web Application Controller Article #4: Asp.Net MVC Enterprise Quality Web Repository Layer Article #5: Asp.Net MVC Enterprise Quality Web with Entity Framework Article #6: Asp.Net MVC Enterprise Quality Layers Article #7: Asp.Net MVC Enterprise Quality Web Security