本文通过IDistributedCache的接口方法,实现Redis与MemoryCache统一帮助类。只需要在配置文件中简单的配置一下,就可以实现Redis与MemoryCache的切换。
| 方法 | 说明 |
|---|---|
| Get(String) | 获取具有给定键的值。 |
| GetAsync(String, CancellationToken) | 获取具有给定键的值。 |
| Refresh(String) | 基于缓存中某个值的键刷新该值,并重置其可调到期超时(如果有)。 |
| RefreshAsync(String, CancellationToken) | 基于缓存中某个值的键刷新该值,并重置其可调到期超时(如果有)。 |
| Remove(String) | 删除具有给定键的值。 |
| RemoveAsync(String, CancellationToken) | 删除具有给定键的值。 |
| Set(String, Byte[], DistributedCacheEntryOptions) | 设置具有给定键的值。 |
| SetAsync(String, Byte[], DistributedCacheEntryOptions, CancellationToken) | 设置具有给定键的值。 |
IDistributedCache 还提供了一些扩展方法,本文的帮助类就是通过扩展方法完成的。
| 方法 | 说明 |
|---|---|
| GetString(IDistributedCache, String) | 使用指定的键从指定的缓存中获取字符串。 |
| GetStringAsync(IDistributedCache, String, CancellationToken) | 使用指定的键从指定的缓存异步获取字符串。 |
| Set(IDistributedCache, String, Byte[]) | 使用指定的键设置指定缓存中的字节序列。 |
| SetAsync(IDistributedCache, String, Byte[], CancellationToken) | 使用指定的键异步设置指定缓存中的字节序列。 |
| SetString(IDistributedCache, String, String) | 使用指定的键在指定的缓存中设置字符串。 |
| SetString(IDistributedCache, String, String, DistributedCacheEntryOptions) | 使用指定的键在指定的缓存中设置字符串。 |
| SetStringAsync(IDistributedCache, String, String, DistributedCacheEntryOptions, CancellationToken) | 使用指定的键在指定的缓存中异步设置字符串。 |
| SetStringAsync(IDistributedCache, String, String, CancellationToken) | 使用指定的键在指定的缓存中异步设置字符串。 |
ICache接口提供了设置缓存、获取缓存、删除缓存和刷新缓存的接口方法。
namespace CacheHelper
{public interface ICache{#region 设置缓存 /// /// 设置缓存/// /// 缓存Key/// 值void SetCache(string key, object value);/// /// 设置缓存/// /// 缓存Key/// 值Task SetCacheAsync(string key, object value);/// /// 设置缓存/// 注:默认过期类型为绝对过期/// /// 缓存Key/// 值/// 过期时间间隔void SetCache(string key, object value, TimeSpan timeout);/// /// 设置缓存/// 注:默认过期类型为绝对过期/// /// 缓存Key/// 值/// 过期时间间隔Task SetCacheAsync(string key, object value, TimeSpan timeout);/// /// 设置缓存/// 注:默认过期类型为绝对过期/// /// 缓存Key/// 值/// 过期时间间隔/// 过期类型 void SetCache(string key, object value, TimeSpan timeout, ExpireType expireType);/// /// 设置缓存/// 注:默认过期类型为绝对过期/// /// 缓存Key/// 值/// 过期时间间隔/// 过期类型 Task SetCacheAsync(string key, object value, TimeSpan timeout, ExpireType expireType);#endregion#region 获取缓存/// /// 获取缓存/// /// 缓存Keystring GetCache(string key);/// /// 获取缓存/// /// 缓存KeyTask GetCacheAsync(string key);/// /// 获取缓存/// /// 缓存KeyT GetCache(string key);/// /// 获取缓存/// /// 缓存KeyTask GetCacheAsync(string key);#endregion#region 删除缓存/// /// 清除缓存/// /// 缓存Keyvoid RemoveCache(string key);/// /// 清除缓存/// /// 缓存KeyTask RemoveCacheAsync(string key);#endregion#region 刷新缓存/// /// 刷新缓存/// /// 缓存Keyvoid RefreshCache(string key);/// /// 刷新缓存/// /// 缓存KeyTask RefreshCacheAsync(string key);#endregion}
}
ExpireType枚举标识缓存的过期类型,分为绝对过期与相对过期两个类型。
绝对过期:即自创建一段时间后就过期
相对过期:即该键未被访问后一段时间后过期,若此键一直被访问则过期时间自动延长。
namespace CacheHelper
{public enum ExpireType{/// /// 绝对过期/// 注:即自创建一段时间后就过期/// Absolute,/// /// 相对过期/// 注:即该键未被访问后一段时间后过期,若此键一直被访问则过期时间自动延长/// Relative,}
}
是使用MemoryCache,还是Redis,MemoryCache不支持分布式,Redis支持分布式。
namespace CacheHelper
{public enum CacheType{/// /// 使用内存缓存(不支持分布式)/// Memory,/// /// 使用Redis缓存(支持分布式)/// Redis}
}
namespace CacheHelper
{public class CacheHelper : ICache{readonly IDistributedCache _cache;public CacheHelper(IDistributedCache cache){_cache = cache;}protected string BuildKey(string idKey){return $"Cache_{GetType().FullName}_{idKey}";}public void SetCache(string key, object value){string cacheKey = BuildKey(key);_cache.SetString(cacheKey, value.ToJson());}public async Task SetCacheAsync(string key, object value){string cacheKey = BuildKey(key);await _cache.SetStringAsync(cacheKey, value.ToJson());}public void SetCache(string key, object value, TimeSpan timeout){string cacheKey = BuildKey(key);_cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions{AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)});}public async Task SetCacheAsync(string key, object value, TimeSpan timeout){string cacheKey = BuildKey(key);await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions{AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)});}public void SetCache(string key, object value, TimeSpan timeout, ExpireType expireType){string cacheKey = BuildKey(key);if (expireType == ExpireType.Absolute){//这里没转换标准时间,Linux时区会有问题?_cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions{AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)});}else{_cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions{AbsoluteExpirationRelativeToNow = timeout});}}public async Task SetCacheAsync(string key, object value, TimeSpan timeout, ExpireType expireType){string cacheKey = BuildKey(key);if (expireType == ExpireType.Absolute){//这里没转换标准时间,Linux时区会有问题?await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions{AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)});}else{await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions{AbsoluteExpirationRelativeToNow = timeout});}}public string GetCache(string idKey){if (idKey.IsNullOrEmpty()){return null;}string cacheKey = BuildKey(idKey);var cache = _cache.GetString(cacheKey);return cache;}public async Task GetCacheAsync(string key){if (key.IsNullOrEmpty()){return null;}string cacheKey = BuildKey(key);var cache = await _cache.GetStringAsync(cacheKey);return cache;}public T GetCache(string key){var cache = GetCache(key);if (!cache.IsNullOrEmpty()){return cache.ToObject();}return default(T);}public async Task GetCacheAsync(string key){var cache = await GetCacheAsync(key);if (!string.IsNullOrEmpty(cache)){return cache.ToObject();}return default(T);}public void RemoveCache(string key){_cache.Remove(BuildKey(key));}public async Task RemoveCacheAsync(string key){await _cache.RemoveAsync(BuildKey(key));}public void RefreshCache(string key){_cache.Refresh(BuildKey(key));}public async Task RefreshCacheAsync(string key){await _cache.RefreshAsync(BuildKey(key));}}
}
CacheHelper 中,自定义了一个string的扩展方法ToObject。ToObject扩展方法使用了 Newtonsoft.Json。
///
/// 将Json字符串反序列化为对象
///
/// 对象类型
/// Json字符串
///
public static T ToObject(this string jsonStr)
{return JsonConvert.DeserializeObject(jsonStr);
}
Redis依赖我使用的是Caching.CSRedis,安装依赖:
PM> Install-Package Caching.CSRedis -Version 3.6.90
在appsettings.json中,对缓存进行配置:
"Cache": {"CacheType": "Memory", // "Memory OR Redis""RedisEndpoint": "127.0.0.1:6379" //Redis节点地址,定义详见 https://github.com/2881099/csredis},
如果要使用MemoryCache,CacheType就设置为Memory,如果要使用Redis,CacheType就设置为Redis。如果设置为Redis的话,还需要配置RedisEndpoint,保证Redis节点可用。
编写一个名为CacheOptions的类。用于获取配置文件的配置节内容
namespace CacheHelper
{public class CacheOptions{public CacheType CacheType { get; set; }public string RedisEndpoint { get; set; }}
}
编写一个IHostBuilder的扩展方法UseCache,用于注入MemoryCache或是Redis
public static IHostBuilder UseCache(this IHostBuilder hostBuilder)
{hostBuilder.ConfigureServices((buidlerContext, services) =>{var cacheOption = buidlerContext.Configuration.GetSection("Cache").Get();switch (cacheOption.CacheType){case CacheType.Memory: services.AddDistributedMemoryCache(); break;case CacheType.Redis:{var csredis = new CSRedisClient(cacheOption.RedisEndpoint);RedisHelper.Initialization(csredis);services.AddSingleton(csredis);services.AddSingleton(new CSRedisCache(RedisHelper.Instance));}; break;default: throw new Exception("缓存类型无效");}});return hostBuilder;
}
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseCache();
public class HomeController
{readonly ICache _cache;public HomeController(ICache cache,){_cache = cache;}public async Task CacheTest(string key){string cache_value = "hello cache";//同步方法_cache.SetCache(key,cache_value );string v = _cache.GetCache(key);_cache.RemoveCache(key);//异步方法await _cache.SetCacheAsync(key,cache_value );string val = await _cache.GetCacheAsync(key);await _cache.RemoveCacheAsync(key);}
}
暂无,下次再会