上一篇讲解了Redis的搭建及ServiceStack.Redis 与 StackExchange.Reids 的区别https://blog.csdn.net/qq_39569480/article/details/105249607
这篇文章遗我们来说下使用Microsoft.Extensions.Caching.StackExchangeRedis来对redis进行操作及帮助类。
首先在windows上安装redis 在上边连接中有教程 .
创建webapi项目
在包管理器中安装Microsoft.Extensions.Caching.StackExchangeRedis
在appsettings.json中添加连接字符串:(redis连接字符串)
ps:这里需要特别注意,与普通链接redis不同的是,如果我们想指定数据库名称,不能直接在连接字符串中追加,需要在Program中指定。
"ConnectionStrings": {
"Redis": "123.123.33.22:6379,password=123456!,ConnectTimeout=15000,SyncTimeout=5000"
},
定义一个接口
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="minutes">过期时间间隔 以分钟为单位</param>
void SetCache(string key, object value,int minutes);
/// <summary>
/// 设置缓存
/// 注:默认过期类型为绝对过期
/// </summary>
/// <param name="key">缓存Key</param>
/// <param name="value">值</param>
/// <param name="timeout">过期时间间隔 以分钟为单位</param>
Task SetCacheAsync(string key, object value, int minutes);
/// <summary>
/// 设置缓存
/// 注:默认过期类型为绝对过期
/// </summary>
/// <param name="key">缓存Key</param>
/// <param name="value">值</param>
/// <param name="minutes">过期时间间隔 以分钟为单位</param>
/// <param name="expireType">过期类型</param>
void SetCache(string key, object value, int minutes, ExpireType expireType);
/// <summary>
/// 设置缓存
/// 注:默认过期类型为绝对过期
/// </summary>
/// <param name="key">缓存Key</param>
/// <param name="value">值</param>
/// <param name="minutes">过期时间间隔 以分钟为单位</param>
/// <param name="expireType">过期类型</param>
Task SetCacheAsync(string key, object value, int minutes, 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"></param>
/// <param name="value"></param>
/// <param name="minutes"></param>
/// <param name="expireType">过期类型,默认绝对过期</param>
/// <returns></returns>
Task<string> GetOrAddAsync(string key, object value, int minutes, ExpireType expireType = 0);
/// <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);
/// <summary>
/// 获取泛型缓存,没有则添加
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="minutes"></param>
/// <param name="expireType">过期类型,默认绝对过期</param>
/// <returns></returns>
Task<T> GetOrAddAsync<T>(string key, Func<Task<T>> valueFactory, int minutes, ExpireType expireType = 0);
/// <summary>
/// 获取泛型集合缓存,没有则添加
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="valueFactory"></param>
/// <param name="minutes"></param>
/// <param name="expireType"></param>
/// <returns></returns>
Task<List<T>> GetOrAddListAsync<T>(string key, Func<Task<List<T>>> valueFactory, int minutes, ExpireType expireType = 0);
#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
}
实现接口中定义的方法
public class CacheHelper : ICache
{
readonly IDistributedCache _cache;
public CacheHelper(IDistributedCache cache)
{
_cache = cache;
}
protected string BuildKey(string idKey)
{
return $"Cache_{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,int minutes)
{
string cacheKey = BuildKey(key);
_cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
});
}
public async Task SetCacheAsync(string key, object value, int minutes)
{
string cacheKey = BuildKey(key);
await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
});
}
public void SetCache(string key, object value, int minutes, ExpireType expireType)
{
string cacheKey = BuildKey(key);
if (expireType == ExpireType.Absolute)
{
//这里没转换标准时间,Linux时区会有问题?
_cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
});
}
else
{
_cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
});
}
}
public async Task SetCacheAsync(string key, object value, int minutes, ExpireType expireType)
{
string cacheKey = BuildKey(key);
if (expireType == ExpireType.Absolute)
{
//这里没转换标准时间,Linux时区会有问题?
await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
});
}
else
{
await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
});
}
}
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 async Task<string> GetOrAddAsync(string key,object value,int minutes, ExpireType expireType=0)
{
if (key.IsNullOrEmpty()) return null;
string cacheKey = BuildKey(key);
var cache = await _cache.GetStringAsync(cacheKey);
if (cache==null)
{
string json= value.ToJson();
if (expireType == ExpireType.Absolute)
{
//这里没转换标准时间,Linux时区会有问题?
await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
});
}
else
{
await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
});
}
return json;
}
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 async Task<T> GetOrAddAsync<T>(string key, Func<Task<T>> valueFactory, int minutes, ExpireType expireType = 0)
{
if (key.IsNullOrEmpty()) return default(T);
string cacheKey = BuildKey(key);
var cache = await _cache.GetStringAsync(cacheKey);
if (cache == null)
{//缓存中没有数据去查实际的数据
T value = await valueFactory();
string json = value.ToJson();
//如果查实际的数据还是没有那么直接返回空
if (string.IsNullOrWhiteSpace(json)) return cache.ToObject<T>();
if (expireType == ExpireType.Absolute)
{
//这里没转换标准时间,Linux时区会有问题?
await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
});
}
else
{
await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
});
}
return json.ToObject<T>();
}
return cache.ToObject<T>();
}
public async Task<List<T>> GetOrAddListAsync<T>(string key, Func<Task<List<T>>> valueFactory, int minutes, ExpireType expireType = 0)
{
if (key.IsNullOrEmpty()) return default(List<T>);
string cacheKey = BuildKey(key);
var cache = await _cache.GetStringAsync(cacheKey);
if (cache == null)
{//缓存中没有数据去查实际的数据
List<T> value = await valueFactory();
string json = value.ToJson();
//如果查实际的数据还是没有那么直接返回空
if (string.IsNullOrWhiteSpace(json)) return cache.ToObject<List<T>>();
if (expireType == ExpireType.Absolute)
{
//这里没转换标准时间,Linux时区会有问题?
await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
});
}
else
{
await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
});
}
return json.ToObject<List<T>>();
}
return cache.ToObject<List<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));
}
}
定义一个枚举的过期类型
public enum ExpireType
{
/// <summary>
/// 绝对过期
/// 注:即自创建一段时间后就过期
/// </summary>
Absolute,
/// <summary>
/// 相对过期
/// 注:即该键未被访问后一段时间后过期,若此键一直被访问则过期时间自动延长
/// </summary>
Relative,
}
定义一个string的扩展方法
public static class ValueToObject
{
/// <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);
}
/// <summary>
/// 将字符串序列化为json
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string ToJson(this object str)
{
return JsonConvert.SerializeObject(str);
}
}
在Program.cs文件中注入并添加redis
builder.Services.AddScoped(typeof(ICache), typeof(CacheHelper));//注入
var redisOptions = ConfigurationOptions.Parse(builder.Configuration.GetConnectionString("Redis"));
redisOptions.DefaultDatabase = 1; // 选择数据库索引为1的数据库,默认是0
builder.Services.AddStackExchangeRedisCache(o =>
{
//redis连接
o.ConfigurationOptions = redisOptions;//指定数据库
//o.Configuration = builder.Configuration.GetConnectionString("Redis");不指定数据库可以直接连接
//设置缓存key的前缀
//o.InstanceName = "";
});
控制器中使用
[Route("demo")]
[ApiController]
//[Authorize]
public class DemoController : ControllerBase
{
private readonly IDemoService _demo;
public DemoController(IDemoService demo)
{
_demo = demo;
}
/// <summary>
/// 获取详情
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet]
public async Task<dynamic> Get(int id)
{
DemoGetOutPut demo=await _cache.GetOrAddAsync<DemoGetOutPut>($"demo{id}", async () => await GetDemo(id),20);
return demo;
}
public async Task<dynamic> GetDemo(int id)
{
return new { name= "张三", age= 18 };
}
}