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