- A+
所属分类:.NET技术
本文通过IDistributedCache
的接口方法,实现Redis与MemoryCache统一帮助类。只需要在配置文件中简单的配置一下,就可以实现Redis与MemoryCache的切换。
目录
IDistributedCache
IDistributedCache 方法:
方法 | 说明 |
---|---|
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
还提供了一些扩展方法,本文的帮助类就是通过扩展方法完成的。
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 接口
ICache接口提供了设置缓存、获取缓存、删除缓存和刷新缓存的接口方法。
namespace CacheHelper { public interface ICache { #region 设置缓存 /// <summary> /// 设置缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">值</param> void SetCache(string key, object value); /// <summary> /// 设置缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">值</param> Task SetCacheAsync(string key, object value); /// <summary> /// 设置缓存 /// 注:默认过期类型为绝对过期 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">值</param> /// <param name="timeout">过期时间间隔</param> void SetCache(string key, object value, TimeSpan timeout); /// <summary> /// 设置缓存 /// 注:默认过期类型为绝对过期 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">值</param> /// <param name="timeout">过期时间间隔</param> Task SetCacheAsync(string key, object value, TimeSpan timeout); /// <summary> /// 设置缓存 /// 注:默认过期类型为绝对过期 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">值</param> /// <param name="timeout">过期时间间隔</param> /// <param name="expireType">过期类型</param> void SetCache(string key, object value, TimeSpan timeout, ExpireType expireType); /// <summary> /// 设置缓存 /// 注:默认过期类型为绝对过期 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">值</param> /// <param name="timeout">过期时间间隔</param> /// <param name="expireType">过期类型</param> Task SetCacheAsync(string key, object value, TimeSpan timeout, ExpireType expireType); #endregion #region 获取缓存 /// <summary> /// 获取缓存 /// </summary> /// <param name="key">缓存Key</param> string GetCache(string key); /// <summary> /// 获取缓存 /// </summary> /// <param name="key">缓存Key</param> Task<string> GetCacheAsync(string key); /// <summary> /// 获取缓存 /// </summary> /// <param name="key">缓存Key</param> T GetCache<T>(string key); /// <summary> /// 获取缓存 /// </summary> /// <param name="key">缓存Key</param> Task<T> GetCacheAsync<T>(string key); #endregion #region 删除缓存 /// <summary> /// 清除缓存 /// </summary> /// <param name="key">缓存Key</param> void RemoveCache(string key); /// <summary> /// 清除缓存 /// </summary> /// <param name="key">缓存Key</param> Task RemoveCacheAsync(string key); #endregion #region 刷新缓存 /// <summary> /// 刷新缓存 /// </summary> /// <param name="key">缓存Key</param> void RefreshCache(string key); /// <summary> /// 刷新缓存 /// </summary> /// <param name="key">缓存Key</param> Task RefreshCacheAsync(string key); #endregion } }
ExpireType枚举
ExpireType枚举标识缓存的过期类型,分为绝对过期
与相对过期
两个类型。
绝对过期:即自创建一段时间后就过期
相对过期:即该键未被访问后一段时间后过期,若此键一直被访问则过期时间自动延长。
namespace CacheHelper { public enum ExpireType { /// <summary> /// 绝对过期 /// 注:即自创建一段时间后就过期 /// </summary> Absolute, /// <summary> /// 相对过期 /// 注:即该键未被访问后一段时间后过期,若此键一直被访问则过期时间自动延长 /// </summary> Relative, } }
CacheType 枚举
是使用MemoryCache
,还是Redis
,MemoryCache
不支持分布式,Redis
支持分布式。
namespace CacheHelper { public enum CacheType { /// <summary> /// 使用内存缓存(不支持分布式) /// </summary> Memory, /// <summary> /// 使用Redis缓存(支持分布式) /// </summary> Redis } }
CacheHelper 缓存帮助类
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<string> GetCacheAsync(string key) { if (key.IsNullOrEmpty()) { return null; } string cacheKey = BuildKey(key); var cache = await _cache.GetStringAsync(cacheKey); return cache; } public T GetCache<T>(string key) { var cache = GetCache(key); if (!cache.IsNullOrEmpty()) { return cache.ToObject<T>(); } return default(T); } public async Task<T> GetCacheAsync<T>(string key) { var cache = await GetCacheAsync(key); if (!string.IsNullOrEmpty(cache)) { return cache.ToObject<T>(); } 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<T>()
。ToObject<T>()
扩展方法使用了 Newtonsoft.Json
。
/// <summary> /// 将Json字符串反序列化为对象 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="jsonStr">Json字符串</param> /// <returns></returns> public static T ToObject<T>(this string jsonStr) { return JsonConvert.DeserializeObject<T>(jsonStr); }
CacheHelper 的使用方法
安装Redis依赖
Redis依赖我使用的是Caching.CSRedis
,安装依赖:
PM> Install-Package Caching.CSRedis -Version 3.6.90
配置appsettings.json
在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配置
编写一个名为CacheOptions的类。用于获取配置文件的配置节内容
namespace CacheHelper { public class CacheOptions { public CacheType CacheType { get; set; } public string RedisEndpoint { get; set; } } }
IHostBuilder扩展方法UseCache
编写一个IHostBuilder的扩展方法UseCache,用于注入MemoryCache
或是Redis
public static IHostBuilder UseCache(this IHostBuilder hostBuilder) { hostBuilder.ConfigureServices((buidlerContext, services) => { var cacheOption = buidlerContext.Configuration.GetSection("Cache").Get<CacheOptions>(); 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<IDistributedCache>(new CSRedisCache(RedisHelper.Instance)); }; break; default: throw new Exception("缓存类型无效"); } }); return hostBuilder; }
Program.cs中引用
var builder = WebApplication.CreateBuilder(args); builder.Host.UseCache();
CacheHelper的使用。
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<string>(key); _cache.RemoveCache(key); //异步方法 await _cache.SetCacheAsync(key,cache_value ); string val = await _cache.GetCacheAsync<string>(key); await _cache.RemoveCacheAsync(key); } }
总结
暂无,下次再会!
欢迎大家关注我的微信公众号,一起进步,一起成长