using System; using System.Runtime.Caching; namespace Default { public class CacheHelper { private static readonly ObjectCache Cache = MemoryCache.Default; // private static readonly ObjectCache ObjectCache = new MemoryCache("WebApiCache"); private static ConcurrentDictionary<string, object> keyLocks = new ConcurrentDictionary<string, object>(); public static T Get<T>(string key) { return (T)Cache.Get(key); } public static void Add(string key, object value, int minutes) { var item = new CacheItem(key) {Value = value}; var policy = new CacheItemPolicy {AbsoluteExpiration = DateTime.UtcNow.AddMinutes(minutes)}; Cache.Add(item, policy); } public static T GetFromCache<T>(string key) { return (T)(ObjectCache.GetCacheItem(key)?.Value); } public static void AddToCacheNonExpiring(string key, object value) { var policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.MaxValue }; var cacheItem = new CacheItem(key, value); ObjectCache.Add(cacheItem, policy); } public static void AddToCacheAbsolute(string key, object value, DateTimeOffset expiresAt) { var policy = new CacheItemPolicy { AbsoluteExpiration = expiresAt }; var cacheItem = new CacheItem(key, value); ObjectCache.Add(cacheItem, policy); } public static async Task<T> CachedItem<T>(string key, Func<Task<T>> generator, TimeSpan validTime) { using (new Locker(key)) { var cacheValue = ObjectCache.GetCacheItem(key)?.Value; if (cacheValue != null) return (T)cacheValue; T result = await generator().ConfigureAwait(false); // Configure await false ensures the function throws errors var cacheItem = new CacheItem(key, result); var policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.Add(validTime) }; ObjectCache.Add(cacheItem, policy); return result; } } public static T CachedItem2<T>(string key, Func<T> generator, TimeSpan validTime) { try { lock (keyLocks.GetOrAdd(key, new object())) { var policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.Add(validTime) }; var cacheValue = ObjectCache.GetCacheItem(key)?.Value; if (cacheValue != null) return (T)cacheValue; // Configure await false ensures the function throws errors; T result = generator(); if (result == null) return default(T); // null can not be cached var cacheItem = new CacheItem(key, result); ObjectCache.Add(cacheItem, policy); return result; } } finally { keyLocks.TryRemove(key, out object _); } } private class CachedData<T> : ICachedItem<T> { public DateTime GeneratedAt { get; set; } public T Result { get; set; } } public ICachedItem<T> CachedItem<T>(string key, Func<T> generator, TimeSpan validTime, TimeSpan regenerateAfter) { var cachedData = (CachedData<T>)ObjectCache.GetCacheItem(key)?.Value; if (cachedData != null) { if (cachedData.GeneratedAt < DateTime.Now.Subtract(regenerateAfter)) { Task.Run(() => { return GenerateNew(key, generator, validTime); }); } return cachedData; } return GenerateNew(key, generator, validTime); } public ICachedItem<T> GenerateNew<T>(string key, Func<T> generator, TimeSpan validTime) { var result = generator(); if (result == null) return default; // null can not be cached var data = new CachedData<T> { GeneratedAt = DateTime.Now, Result = result }; var cacheItem = new CacheItem(key, data); var policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.Add(validTime)}; ObjectCache.Set(cacheItem, policy); return data; } } }
89400cookie-checkC# In-Memory Cache