本文通过IDistributedCache的接口方法,实现RedisMemoryCache统一帮助类。只需要在配置文件中简单的配置一下,就可以实现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,还是RedisMemoryCache不支持分布式,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);
}
}

总结

暂无,下次再会!


最新文章

  1. Tensorflow使用环境配置
  2. [NOIP2013]华容道
  3. centos虚拟机网络配置
  4. android Spinner的简单用法
  5. python作为一种胶水和c/c++
  6. Address already in use的解决方法
  7. Turing Test
  8. HDFS+MapReduce+Hive+HBase十分钟快速入门
  9. Android系统服务-WindowManager
  10. kettle内存溢出
  11. NGINX+UWSGI 莫名发生Nginx 502 Bad Gateway错误的排查过程
  12. NEURAL NETWORKS, PART 2: THE NEURON
  13. 布局文件提示错误“No orientation specified, and the default is horizontal. This is a common so...”
  14. 安装oneproxy实现数据库的读写分离
  15. Java 处理图片 base64 编码的相互转换
  16. Web服务器自定义错误页面
  17. LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal (用中序和后序树遍历来建立二叉树)
  18. 易酷 cms2.5 本地文件包含漏洞 getshell
  19. Chrome自定义滚动条
  20. Spring流行的十大理由

热门文章

  1. Kubernetes实践技巧:升级为集群
  2. 新版本中的hits.total匹配数说明
  3. portainer 1.24.2 升级到 portainer-ce 最新版
  4. Vmware虚拟机设置主机端口映射
  5. 03_配置Java环境变量
  6. Jmeter——BeanShell 内置变量vars、props、prev的使用
  7. flinksql读写redis
  8. PageRank原理分析
  9. Python基础之面向对象:3、继承与派生
  10. Node.js的学习(一)node.js 的介绍