API response caching:
public class CacheBase { protected int _expireDuration; protected long _cacheTimestamp; public int KeyMaxCount { get; set; } public dynamic SingleData { get; set; } public List<dynamic> ListOfData { get; set; } public CacheBase() { KeyMaxCount = 2000; } public bool IsExpire() { if (CurrentTimestamp() - _cacheTimestamp < _expireDuration) { return false; } return true; } protected long CurrentTimestamp() { return (long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; } }
public class Person { public int ID { get; set; } public string Name { get; set; } } public class PersonCache : CacheBase { public PersonCache(List<Person> dataList) { _expireDuration = 20; _cacheTimestamp = CurrentTimestamp(); if (dataList != null) { DataList = dataList.Cast<dynamic>().ToList(); } } }
protected bool IsCacheExpire<U>(ConcurrentDictionary<string, U> cacheDict, string key, out U cache) where U : CacheBase { cache = default(U); if (cacheDict.TryGetValue(key, out cache) && cache != null && !cache.IsExpire()) { return false; } if (cache != null && cacheDict.Count > cache.KeyMaxCount) { CleanCache(cacheDict); } return true; } protected void CleanCache<U>(ConcurrentDictionary<string, U> cacheDict) where U : CacheBase { if (cacheDict == null || cacheDict.Count == 0) { return; } NLog.Logger logger = NLog.LogManager.GetLogger("CleanCache"); StringBuilder log = new StringBuilder(); try { LogCache(cacheDict, ref log); U got; foreach (var cache in cacheDict) { if (cache.Value != null && cache.Value.IsExpire()) { cacheDict.TryRemove(cache.Key, out got); } } log.AppendLine("[After clean]"); LogCache(cacheDict, ref log); logger.Info(log.ToString()); } catch (Exception ex) { logger.Error(ex, log.ToString()); } } protected void LogCache<U>(ConcurrentDictionary<string, U> cacheDict, ref StringBuilder log) { if (cacheDict == null || cacheDict.Count == 0) { return; } log.AppendFormat("Cache Count: {0}", cacheDict.Count).AppendLine(); log.Append("Keys: "); foreach (var cache in cacheDict) { log.AppendFormat("{0},", cache.Key); } log.AppendLine(); } protected void AddNewCache<T>(ConcurrentDictionary<int, T> cacheDict, int key, T data) { //To reset the Cache Timestamp. T cache; if (cacheDict.TryGetValue(key, out cache)) { cacheDict.TryRemove(key, out cache); } cacheDict.TryAdd(key, data); }
private static ConcurrentDictionary<int, PersonCache> _personCacheDict = new ConcurrentDictionary<int, PersonCache>(); public List<Person> GetPeople(int keys) { #region Query from cache uncachedKeys = new List<int>(); List<Person> rtn = new List<Person>(); foreach (int key in keys) { PersonCache cache; if (!IsCacheExpire<PersonCache>(_personCacheDict, key, out cache) && cache.DataList != null) { cache.DataList.ForEach(data => rtn.Add(data)); } else { uncachedKeys.Add(key); } } #endregion #region Query from db List<Person> dbDataList = QueryFromDB(uncachedKeys); if (dbDataList.Count == 0) { return rtn; } #endregion #region Write into the cache foreach (int key in uncachedKeys) { List<Person> list = (from p in dbDataList where p.ID == key select p).ToList(); AddNewCache(_personCacheDict, key, new PersonCache(list)); } #endregion return rtn.AddRange(dbDataList); }