1、ICache的Redis實現沒有放在'Framework.Cache/Logic'中。如果是以前,我會認為這樣不好。我會這樣做,'Framework.Cache'項目引用Redis項目或直接從Nuget安裝Redis,
把實現定義在‘Framework.Cache/Logic’中,這樣結構看起來很順眼,‘這算是高內聚么!!!’。不過自從接觸了IOC后,現在這樣的結構似乎也很合理,沒什么違和感。
這就好似把‘IRepository’和‘Repositories’,一個放在Domain,一個放在Infrastructure
2、當前比較穩定的Redis客戶端(開源的程序包)有ServiceStack.Redis 和 StackExchange.Redis。我都用了一下,ServiceStatck的
比較好用,不過我感覺后者的性能應該會稍好點
3、關於ServiceStack.Redis中的接口,IRedisClient,ICacheClient,IRedisTypedClient<T>,IEntityStore<T>,IEntityStore。
這些“亂七八糟”的接口和CRUD都有關系,中的有些方法看似好像是重復的,后續希望能整理出一篇結合源碼,理論點的文章

一、Framework.Cache
接口ICache,定義緩存操作開放的方法
1 public interface ICache 2 { 3 /// <summary> 4 /// Gets all entries in the cache 5 /// </summary> 6 IEnumerable<KeyValuePair<string, object>> Entries { get; } 7 8 /// <summary> 9 /// Gets a cache item associated with the specified key or adds the item 10 /// if it doesn't exist in the cache. 11 /// </summary> 12 /// <typeparam name="T">The type of the item to get or add</typeparam> 13 /// <param name="key">The cache item key</param> 14 /// <param name="baseMethod">Func which returns value to be added to the cache</param> 15 /// <returns>Cached item value</returns> 16 T Get<T>(string key, Func<T> baseMethod); 17 18 /// <summary> 19 /// Gets a cache item associated with the specified key or adds the item 20 /// if it doesn't exist in the cache. 21 /// </summary> 22 /// <typeparam name="T">The type of the item to get or add</typeparam> 23 /// <param name="key">The cache item key</param> 24 /// <param name="baseMethod">Func which returns value to be added to the cache</param> 25 /// <param name="cacheTime">Expiration time in minutes</param> 26 /// <returns>Cached item value</returns> 27 T Get<T>(string key, Func<T> baseMethod, int cacheTime); 28 29 /// <summary> 30 /// Gets a value indicating whether an item associated with the specified key exists in the cache 31 /// </summary> 32 /// <param name="key">key</param> 33 /// <returns>Result</returns> 34 bool Contains(string key); 35 36 /// <summary> 37 /// Removes the value with the specified key from the cache 38 /// </summary> 39 /// <param name="key">/key</param> 40 void Remove(string key); 41 }
二、基於‘ServiceStack.Redis’的緩存實現
1 public class SSRedisCache : ICache 2 { 3 private const string REGION_NAME = "$#SSRedisCache#$"; 4 private const int _DefaultCacheTime = 30; 5 private readonly static object s_lock = new object(); 6 7 private IRedisClient GetClient() 8 { 9 return RedisManager.GetClient(); 10 } 11 12 private IRedisClient GetReadOnlyClient() 13 { 14 return RedisManager.GetReadOnlyClient(); 15 } 16 17 public IEnumerable<KeyValuePair<string, object>> Entries 18 { 19 get { throw new NotImplementedException(); } 20 } 21 22 public T Get<T>(string key, Func<T> baseMethod) 23 { 24 return Get<T>(key, baseMethod, _DefaultCacheTime); 25 } 26 27 public T Get<T>(string key, Func<T> baseMethod, int cacheTime) 28 { 29 using (var redisClient = GetClient()) 30 { 31 key = BuildKey(key); 32 33 if (redisClient.ContainsKey(key)) 34 { 35 return redisClient.Get<T>(key); 36 } 37 else 38 { 39 lock (s_lock) 40 { 41 if (!redisClient.ContainsKey(key)) 42 { 43 var value = baseMethod(); 44 if (value != null) //請區別null與String.Empty 45 { 46 redisClient.Set<T>(key, value, TimeSpan.FromMinutes(cacheTime)); 47 //redisClient.Save(); 48 } 49 return value; 50 } 51 return redisClient.Get<T>(key); 52 } 53 } 54 } 55 } 56 57 public bool Contains(string key) 58 { 59 using (var redisClient = GetReadOnlyClient()) 60 { 61 return redisClient.ContainsKey(BuildKey(key)); 62 } 63 } 64 65 public void Remove(string key) 66 { 67 using (var redisClient = GetClient()) 68 { 69 redisClient.Remove(BuildKey(key)); 70 } 71 } 72 73 private string BuildKey(string key) 74 { 75 return string.IsNullOrEmpty(key) ? null : REGION_NAME + key; 76 } 77 78 }
三、基於‘StackExchange.Redis’的緩存實現
1 <?xml version="1.0" encoding="utf-8"?> 2 <packages> 3 <package id="MsgPack.Cli" version="0.6.8" targetFramework="net45" /> 4 <package id="StackExchange.Redis" version="1.0.488" targetFramework="net45" /> 5 <package id="StackExchange.Redis.Extensions.Core" version="1.3.2.0" targetFramework="net45" /> 6 <package id="StackExchange.Redis.Extensions.MsgPack" version="1.3.2.0" targetFramework="net45" /> 7 </packages>
1 public class SERedisCache : ICache 2 { 3 private const string REGION_NAME = "$#SERedisCache#$"; 4 private const int _DefaultCacheTime = 30; 5 private readonly static object s_lock = new object(); 6 7 private StackExchangeRedisCacheClient GetClient() 8 { 9 return new StackExchangeRedisCacheClient(RedisServer.Connection, new MsgPackObjectSerializer()); 10 } 11 12 public IEnumerable<KeyValuePair<string, object>> Entries 13 { 14 get { throw new NotImplementedException(); } 15 } 16 17 public T Get<T>(string key, Func<T> baseMethod) 18 { 19 return Get(key, baseMethod, _DefaultCacheTime); 20 } 21 22 public T Get<T>(string key, Func<T> baseMethod, int cacheTime) 23 { 24 using (var cacheClient = GetClient()) 25 { 26 key = BuildKey(key); 27 28 if (cacheClient.Exists(key)) 29 { 30 return cacheClient.Get<T>(key); 31 } 32 else 33 { 34 lock (s_lock) 35 { 36 if (!cacheClient.Exists(key)) 37 { 38 var value = baseMethod(); 39 if (value != null) //請區別null與String.Empty 40 { 41 cacheClient.Add<T>(key, value, TimeSpan.FromMinutes(cacheTime)); 42 } 43 return value; 44 } 45 return cacheClient.Get<T>(key); 46 } 47 } 48 } 49 } 50 51 public bool Contains(string key) 52 { 53 using (var cacheClient = GetClient()) 54 { 55 return cacheClient.Exists(BuildKey(key)); 56 } 57 } 58 59 public void Remove(string key) 60 { 61 using (var cacheClient = GetClient()) 62 { 63 cacheClient.Remove(BuildKey(key)); 64 } 65 } 66 67 private string BuildKey(string key) 68 { 69 return string.IsNullOrEmpty(key) ? null : REGION_NAME + key; 70 } 71 72 }
完整代碼(稍后) 會在另一篇文章關於Web API中附上
