Last active
August 31, 2016 22:58
-
-
Save dealproc/d7144477c2767c8de89253ad8a87f39e to your computer and use it in GitHub Desktop.
Caching (in-memory and redis)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace {yourapp}.Infrastructure.Caching { | |
public interface ICache { | |
/// <summary> | |
/// Determines whether the specified keyformat contains key. | |
/// </summary> | |
/// <param name="keyformat">The keyformat.</param> | |
/// <param name="arguments">The arguments.</param> | |
/// <returns></returns> | |
bool ContainsKey(string keyformat, params object[] arguments); | |
/// <summary> | |
/// Clears the specified item from the cache. | |
/// </summary> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
void Clear(string keyFormat, params object[] arguments); | |
/// <summary> | |
/// Adds the specified data to the cache for the specified time. | |
/// </summary> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="data">The data.</param> | |
/// <param name="slidingExpiration">The sliding expiration.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
void Add<T>(string keyFormat, T data, TimeSpan slidingExpiration, params object[] arguments); | |
/// <summary> | |
/// Adds the specified data to the cache until specified time. | |
/// </summary> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="data">The data.</param> | |
/// <param name="absoluteExpiration">The absolute expiration.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
void Add<T>(string keyFormat, T data, DateTime absoluteExpiration, params object[] arguments); | |
/// <summary> | |
/// Retrieves the data for the specified key. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
/// <returns>The data for the key if it exists; null otherwise.</returns> | |
CachedObject<T> Retrieve<T>(string keyFormat, params object[] arguments) where T : class; | |
/// <summary> | |
/// Retrieves the data for the specified key. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="retrievalMethod">The method that returns the data in the event it is not cached.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
/// <returns>The data for the key if it exists; null otherwise.</returns> | |
CachedObject<T> Retrieve<T>(Func<T> retrievalMethod, string keyFormat, params object[] arguments) where T : class; | |
/// <summary> | |
/// Retrieves the data for the specified key. The data will be cached on a sliding expiration for the specified timeout | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="retrievalMethod">The method that returns the data in the event it is not cached.</param> | |
/// <param name="slidingExpiration">The sliding expiration.</param> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
/// <returns> | |
/// The data for the key if it exists; null otherwise. | |
/// </returns> | |
CachedObject<T> Retrieve<T>(Func<T> retrievalMethod, TimeSpan slidingExpiration, string keyFormat, params object[] arguments) where T : class; | |
/// <summary> | |
/// Retrieves the data for the specified key. The data will be cached until the date specified | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="retrievalMethod">The retrieval method.</param> | |
/// <param name="absoluteExpiration">The absolute expiration.</param> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="arguments">The arguments.</param> | |
/// <returns></returns> | |
CachedObject<T> Retrieve<T>(Func<T> retrievalMethod, DateTime absoluteExpiration, string keyFormat, params object[] arguments) where T : class; | |
/// <summary> | |
/// Resets the specified key format. | |
/// </summary> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="arguments">The arguments.</param> | |
void Reset(string keyFormat, params object[] arguments); | |
} | |
/// <summary> | |
/// Indicate the relative priority of this item of keeping the item cached. | |
/// </summary> | |
public enum RelativeCachePriority { | |
/// <summary> | |
/// Cache items with this priority level are the most likely to be deleted from the cache as the | |
/// server frees system memory. | |
/// </summary> | |
Low = 1, | |
/// <summary> | |
/// Cache items with this priority level are more likely to be deleted from the cache as the | |
/// server frees system memory than items assigned a Normal priority. | |
/// </summary> | |
BelowNormal = 2, | |
/// <summary> | |
/// Cache items with this priority level are likely to be deleted from the cache | |
/// as the server frees system memory only after those items with Low | |
/// or BelowNormal priority. This is the default. | |
/// </summary> | |
Normal = 3, | |
/// <summary> | |
/// Cache items with this priority level are less likely to be deleted as the | |
/// server frees system memory than those assigned a Normal priority. | |
/// </summary> | |
AboveNormal = 4, | |
/// <summary> | |
/// Cache items with this priority level are the least likely to be deleted from | |
/// the cache as the server frees system memory. | |
/// </summary> | |
High = 5, | |
/// <summary> | |
/// The cache items with this priority level will not be automatically deleted | |
/// from the cache as the server frees system memory | |
/// </summary> | |
NotRemovable = 6, | |
} | |
/// <summary> | |
/// Objects of this class type are objects that have been inserted into the cache. | |
/// This type tells you when that object was created. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
[Serializable] | |
public class CachedObject<T> { | |
private CachedObject() { } | |
/// <summary> | |
/// Initializes a new instance of the <see cref="CachedObject{T}"/> class. | |
/// </summary> | |
/// <param name="o">The o.</param> | |
public CachedObject(T o) { | |
Object = o; | |
CacheDate = DateTime.Now; | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="CachedObject{T}"/> class. | |
/// </summary> | |
/// <param name="o">The o.</param> | |
/// <param name="cacheDate">The cache date.</param> | |
public CachedObject(T o, DateTime cacheDate) { | |
Object = o; | |
CacheDate = cacheDate; | |
} | |
/// <summary> | |
/// Gets the cache date. | |
/// </summary> | |
/// <value> | |
/// The cache date. | |
/// </value> | |
public DateTime CacheDate { get; private set; } | |
/// <summary> | |
/// Gets the object. | |
/// </summary> | |
/// <value> | |
/// The object. | |
/// </value> | |
public T Object { get; private set; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.Caching; | |
namespace {yourapp}.Infrastructure.Caching { | |
public class MemoryCacheWrapper : ICache { | |
private static readonly ObjectCache Cache = MemoryCache.Default; | |
private readonly object _pad = new object(); | |
/// <summary> | |
/// Determines whether the this cache contains the specified key. | |
/// </summary> | |
/// <param name="keyformat">The keyformat.</param> | |
/// <param name="arguments">The arguments.</param> | |
/// <returns></returns> | |
public bool ContainsKey(string keyformat, params object[] arguments) { | |
return Cache.Get(Key(keyformat, arguments)) != null; | |
} | |
/// <summary> | |
/// Clears the specified item from the cache. | |
/// </summary> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
public void Clear(string keyFormat, params object[] arguments) { | |
Cache.Remove(Key(keyFormat, arguments)); | |
} | |
/// <summary> | |
/// Adds the specified data to the cache for the specified time. | |
/// </summary> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="data">The data.</param> | |
/// <param name="slidingExpiration">The sliding expiration.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
public void Add<T>(string keyFormat, T data, TimeSpan slidingExpiration, params object[] arguments) { | |
var policy = new CacheItemPolicy { SlidingExpiration = slidingExpiration }; | |
var cacheable = new CachedObject<T>(data); | |
Cache.Set(Key(keyFormat, arguments), cacheable, policy); | |
} | |
/// <summary> | |
/// Adds the specified data to the cache for the specified time. | |
/// </summary> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="data">The data.</param> | |
/// <param name="absoluteExpiration">The absolute expiration.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
public void Add<T>(string keyFormat, T data, DateTime absoluteExpiration, params object[] arguments) { | |
var policy = new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }; | |
var cacheable = new CachedObject<T>(data); | |
Cache.Set(Key(keyFormat, arguments), cacheable, policy); | |
} | |
/// <summary> | |
/// Retrieves the data for the specified key. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
/// <returns>The data for the key if it exists; null otherwise.</returns> | |
public CachedObject<T> Retrieve<T>(string keyFormat, params object[] arguments) where T : class { | |
var obj = Cache.Get(Key(keyFormat, arguments)); | |
if (obj is CachedObject<T>) | |
return obj as CachedObject<T>; | |
if (obj is T) | |
return new CachedObject<T>(obj as T, DateTime.MinValue); | |
return null; | |
} | |
/// <summary> | |
/// Retrieves the data for the specified key. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="retrievalMethod">The method that returns the data in the event it is not cached.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
/// <returns>The data for the key if it exists; null otherwise.</returns> | |
public CachedObject<T> Retrieve<T>(Func<T> retrievalMethod, string keyFormat, params object[] arguments) where T : class { | |
var policy = new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(15) }; //Default 15 min | |
return Retrieve(retrievalMethod, policy, keyFormat, arguments); | |
} | |
/// <summary> | |
/// Retrieves the data for the specified key. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="slidingExpiration">The sliding expiration.</param> | |
/// <param name="retrievalMethod">The method that returns the data in the event it is not cached.</param> | |
/// <param name="arguments">The arguments for the key format.</param> | |
/// <returns>The data for the key if it exists; null otherwise.</returns> | |
public CachedObject<T> Retrieve<T>(Func<T> retrievalMethod, TimeSpan slidingExpiration, string keyFormat, params object[] arguments) where T : class { | |
var policy = new CacheItemPolicy { SlidingExpiration = slidingExpiration }; | |
return Retrieve(retrievalMethod, policy, keyFormat, arguments); | |
} | |
/// <summary> | |
/// Retrieves the data for the specified key. The data will be cached on a absolute expiration for the specified timeout | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="retrievalMethod">The retrieval method.</param> | |
/// <param name="absoluteExpiration">The absolute expiration.</param> | |
/// <param name="keyFormat">The keyformat.</param> | |
/// <param name="arguments">The arguments.</param> | |
/// <returns></returns> | |
public CachedObject<T> Retrieve<T>(Func<T> retrievalMethod, DateTime absoluteExpiration, string keyFormat, params object[] arguments) where T : class { | |
var policy = new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }; | |
return Retrieve(retrievalMethod, policy, keyFormat, arguments); | |
} | |
/// <summary> | |
/// Resets the cache item(s). | |
/// </summary> | |
/// <param name="keyFormat">The key format.</param> | |
/// <param name="arguments">The arguments.</param> | |
public void Reset(string keyFormat, params object[] arguments) { | |
this.Clear(keyFormat, arguments); | |
} | |
private CachedObject<T> Retrieve<T>(Func<T> retrievalMethod, CacheItemPolicy policy, string keyFormat, params object[] arguments) where T : class { | |
var key = Key(keyFormat, arguments); | |
var item = Cache.Get(key) as CachedObject<T>; | |
if (item != null) | |
return item; | |
lock (_pad) { | |
item = Cache.Get(key) as CachedObject<T>; | |
if (item != null) | |
return item; | |
var obj = retrievalMethod(); | |
if (obj != null) { | |
item = new CachedObject<T>(obj); | |
Cache.Set(key, item, policy); | |
} | |
} | |
return item; | |
} | |
private static string Key(string format, params object[] arguments) { | |
return String.Format(format, arguments); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Reflection; | |
using Newtonsoft.Json; | |
using Newtonsoft.Json.Serialization; | |
using StackExchange.Redis; | |
namespace {yourapp}.Infrastructure.Caching { | |
public class RedisCache : ICache { | |
readonly object _pad = new object(); | |
readonly IDatabase _database; | |
readonly JsonSerializerSettings _settings; | |
public RedisCache(Lazy<ConnectionMultiplexer> connectionFactory) { | |
_database = connectionFactory.Value.GetDatabase(); | |
var resolver = new JsonPrivatePropertiesContractResolver(); | |
_settings = new JsonSerializerSettings { ContractResolver = resolver }; | |
} | |
public void Add<T>(string keyFormat, T data, DateTime absoluteExpiration, params object[] arguments) { | |
var key = Key(keyFormat, arguments); | |
var cacheable = new CachedObject<T>(data); | |
_database.StringSet(key, JsonConvert.SerializeObject(cacheable)); | |
_database.KeyExpire(key, absoluteExpiration); | |
} | |
public void Add<T>(string keyFormat, T data, TimeSpan slidingExpiration, params object[] arguments) { | |
var key = Key(keyFormat, arguments); | |
var cacheable = new CachedObject<T>(data); | |
_database.StringSet(key, JsonConvert.SerializeObject(cacheable)); | |
_database.KeyExpire(key, CalculateSlidingExpiration(slidingExpiration)); | |
} | |
public void Clear(string keyFormat, params object[] arguments) { | |
_database.KeyDelete(Key(keyFormat, arguments)); | |
} | |
public bool ContainsKey(string keyformat, params object[] arguments) { | |
return _database.KeyExists(Key(keyformat, arguments)); | |
} | |
public void Reset(string keyFormat, params object[] arguments) { | |
_database.KeyDelete(Key(keyFormat, arguments)); | |
} | |
public CachedObject<T> Retrieve<T>(string keyFormat, params object[] arguments) where T : class { | |
RedisValue str = default(RedisValue); | |
str = _database.StringGet(Key(keyFormat, arguments)); | |
if (str.HasValue) { | |
return JsonConvert.DeserializeObject<CachedObject<T>>(str, _settings); | |
} | |
return null; | |
} | |
public CachedObject<T> Retrieve<T>(Func<T> retrievalMethod, string keyFormat, params object[] arguments) where T : class { | |
return RetrieveWithSlidingExpiration(retrievalMethod, TimeSpan.FromMinutes(15), keyFormat, arguments); | |
} | |
public CachedObject<T> Retrieve<T>(Func<T> retrievalMethod, DateTime absoluteExpiration, string keyFormat, params object[] arguments) where T : class { | |
return RetrieveWithAbsoluteExpiration(retrievalMethod, absoluteExpiration, keyFormat, arguments); | |
} | |
public CachedObject<T> Retrieve<T>(Func<T> retrievalMethod, TimeSpan slidingExpiration, string keyFormat, params object[] arguments) where T : class { | |
return RetrieveWithSlidingExpiration(retrievalMethod, slidingExpiration, keyFormat, arguments); | |
} | |
private CachedObject<T> RetrieveWithAbsoluteExpiration<T>(Func<T> howToRetrieve, DateTime absoluteExpiration, string keyFormat, params object[] keyFormatArguments) where T : class { | |
var key = Key(keyFormat, keyFormatArguments); | |
CachedObject<T> item = null; | |
RedisValue str = default(RedisValue); | |
str = _database.StringGet(key); | |
if (!str.IsNull) { | |
item = JsonConvert.DeserializeObject<CachedObject<T>>(str, _settings); | |
} else { | |
lock (_pad) { | |
str = _database.StringGet(key); | |
if (!str.IsNull) { | |
item = JsonConvert.DeserializeObject<CachedObject<T>>(str, _settings); | |
} else { | |
var obj = howToRetrieve(); | |
if (obj != null) { | |
item = new CachedObject<T>(obj); | |
_database.StringSet(key, JsonConvert.SerializeObject(item)); | |
_database.KeyExpire(key, absoluteExpiration); | |
} | |
} | |
} | |
} | |
return item; | |
} | |
private CachedObject<T> RetrieveWithSlidingExpiration<T>(Func<T> howToRetrieve, TimeSpan slidingExpiration, string keyFormat, params object[] keyFormatArguments) where T : class { | |
var absToExpire = CalculateSlidingExpiration(slidingExpiration); | |
var item = RetrieveWithAbsoluteExpiration(howToRetrieve, absToExpire, keyFormat, keyFormatArguments); | |
if (item != null) { | |
_database.KeyExpire(Key(keyFormat, keyFormatArguments), absToExpire); | |
} | |
return item; | |
} | |
private static string Key(string format, params object[] arguments) { | |
return string.Format(format, arguments); | |
} | |
private static DateTime CalculateSlidingExpiration(TimeSpan slidingExpiration) { | |
return DateTime.Now.Add(slidingExpiration); | |
} | |
} | |
class JsonPrivatePropertiesContractResolver : DefaultContractResolver { | |
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { | |
var prop = base.CreateProperty(member, memberSerialization); | |
if (!prop.Writable) { | |
var property = member as PropertyInfo; | |
if (property != null) { | |
var hasPrivateSetter = property.GetSetMethod(true) != null; | |
prop.Writable = hasPrivateSetter; | |
} | |
} | |
return prop; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment