https://blog.csdn.net/warrior21st/article/details/62884629
缓存也好,数据库也好,我们就是进行CRUD操作,接口没什么好解释的,注释我写的很明白,这里就列给大家:
# 验证缓存项是否存在
1 ///2 /// 验证缓存项是否存在 3 /// 4 /// 缓存Key 5 ///6 bool Exists(string key); 7 8 /// 9 /// 验证缓存项是否存在(异步方式) 10 /// 11 /// 缓存Key 12 ///13 Task ExistsAsync(string key);
# 添加缓存
1 ///2 /// 添加缓存 3 /// 4 /// 缓存Key 5 /// 缓存Value 6 ///7 bool Add(string key, object value); 8 9 /// 10 /// 添加缓存(异步方式) 11 /// 12 /// 缓存Key 13 /// 缓存Value 14 ///15 Task AddAsync(string key, object value); 16 17 /// 18 /// 添加缓存 19 /// 20 /// 缓存Key 21 /// 缓存Value 22 /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) 23 /// 绝对过期时长 24 ///25 bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte); 26 27 /// 28 /// 添加缓存(异步方式) 29 /// 30 /// 缓存Key 31 /// 缓存Value 32 /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) 33 /// 绝对过期时长 34 ///35 Task AddAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte); 36 37 /// 38 /// 添加缓存 39 /// 40 /// 缓存Key 41 /// 缓存Value 42 /// 缓存时长 43 /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) 44 ///45 bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false); 46 47 /// 48 /// 添加缓存(异步方式) 49 /// 50 /// 缓存Key 51 /// 缓存Value 52 /// 缓存时长 53 /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) 54 ///55 Task AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false);
# 删除缓存
1 ///2 /// 删除缓存 3 /// 4 /// 缓存Key 5 ///6 bool Remove(string key); 7 8 /// 9 /// 删除缓存(异步方式) 10 /// 11 /// 缓存Key 12 ///13 Task RemoveAsync(string key); 14 15 /// 16 /// 批量删除缓存 17 /// 18 /// 缓存Key集合 19 ///20 void RemoveAll(IEnumerable keys); 21 22 /// 23 /// 批量删除缓存(异步方式) 24 /// 25 /// 缓存Key集合 26 ///27 Task RemoveAllAsync(IEnumerable keys);
# 获取缓存
1 ///2 /// 获取缓存 3 /// 4 /// 缓存Key 5 ///6 T Get (string key) where T : class; 7 8 /// 9 /// 获取缓存(异步方式) 10 /// 11 /// 缓存Key 12 ///13 Task GetAsync (string key) where T : class; 14 15 /// 16 /// 获取缓存 17 /// 18 /// 缓存Key 19 ///20 object Get(string key); 21 22 /// 23 /// 获取缓存(异步方式) 24 /// 25 /// 缓存Key 26 ///27 Task
# 修改缓存
1 ///2 /// 修改缓存 3 /// 4 /// 缓存Key 5 /// 新的缓存Value 6 ///7 bool Replace(string key, object value); 8 9 /// 10 /// 修改缓存(异步方式) 11 /// 12 /// 缓存Key 13 /// 新的缓存Value 14 ///15 Task ReplaceAsync(string key, object value); 16 17 /// 18 /// 修改缓存 19 /// 20 /// 缓存Key 21 /// 新的缓存Value 22 /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) 23 /// 绝对过期时长 24 ///25 bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte); 26 27 /// 28 /// 修改缓存(异步方式) 29 /// 30 /// 缓存Key 31 /// 新的缓存Value 32 /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) 33 /// 绝对过期时长 34 ///35 Task ReplaceAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte); 36 37 /// 38 /// 修改缓存 39 /// 40 /// 缓存Key 41 /// 新的缓存Value 42 /// 缓存时长 43 /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) 44 ///45 bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false); 46 47 /// 48 /// 修改缓存(异步方式) 49 /// 50 /// 缓存Key 51 /// 新的缓存Value 52 /// 缓存时长 53 /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) 54 ///55 Task ReplaceAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false);
MemoryCache 这个比较简单,有微软比较完善的文档和一些比较好的文章,这个大家都用好久了。
我们新建一个缓存实现类 MemoryCacheService 实现接口 ICacheService
public class MemoryCacheService :ICacheService { }
通过构造器注入 IMemoryCache:
protected IMemoryCache _cache;
public MemoryCacheService(IMemoryCache cache)
{
_cache = cache;
}
实现接口的方法,我们的方法都带有 异步 和 同步 两种,我们节约篇章和时间,异步的就不大家写了,大家自己添加一下就好。
# 验证缓存项是否存在
在MemoryCache中,我们是通过 TryGetValue 来检测 Key是否存在的
1 ///2 /// 验证缓存项是否存在 3 /// 4 /// 缓存Key 5 ///6 public bool Exists(string key) 7 { 8 if (key == null) 9 { 10 throw new ArgumentNullException(nameof(key)); 11 } 12 object cached; 13 return _cache.TryGetValue(key,out cached); 14 }
# 添加缓存
三个添加方法 :
1 ///2 /// 添加缓存 3 /// 4 /// 缓存Key 5 /// 缓存Value 6 ///7 public bool Add(string key, object value) 8 { 9 if (key == null) 10 { 11 throw new ArgumentNullException(nameof(key)); 12 } 13 if (value == null) 14 { 15 throw new ArgumentNullException(nameof(value)); 16 } 17 _cache.Set(key, value); 18 return Exists(key); 19 } 20 /// 21 /// 添加缓存 22 /// 23 /// 缓存Key 24 /// 缓存Value 25 /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) 26 /// 绝对过期时长 27 ///28 public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) 29 { 30 if (key == null) 31 { 32 throw new ArgumentNullException(nameof(key)); 33 } 34 if (value == null) 35 { 36 throw new ArgumentNullException(nameof(value)); 37 } 38 _cache.Set(key, value, 39 new MemoryCacheEntryOptions() 40 .SetSlidingExpiration(expiresSliding) 41 .SetAbsoluteExpiration(expiressAbsoulte) 42 ); 43 44 return Exists(key); 45 } 46 /// 47 /// 添加缓存 48 /// 49 /// 缓存Key 50 /// 缓存Value 51 /// 缓存时长 52 /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) 53 ///54 public bool Add(string key, object value, TimeSpan expiresIn,bool isSliding = false) 55 { 56 if (key == null) 57 { 58 throw new ArgumentNullException(nameof(key)); 59 } 60 if (value == null) 61 { 62 throw new ArgumentNullException(nameof(value)); 63 } 64 if (isSliding) 65 _cache.Set(key, value, 66 new MemoryCacheEntryOptions() 67 .SetSlidingExpiration(expiresIn) 68 ); 69 else 70 _cache.Set(key, value, 71 new MemoryCacheEntryOptions() 72 .SetAbsoluteExpiration(expiresIn) 73 ); 74 75 return Exists(key); 76 }
# 删除缓存
单个删除 和 批量删除
1 ///2 /// 删除缓存 3 /// 4 /// 缓存Key 5 ///6 public bool Remove(string key) 7 { 8 if (key == null) 9 { 10 throw new ArgumentNullException(nameof(key)); 11 } 12 _cache.Remove(key); 13 14 return !Exists(key); 15 } 16 /// 17 /// 批量删除缓存 18 /// 19 /// 缓存Key集合 20 ///21 public void RemoveAll(IEnumerable keys) 22 { 23 if (keys == null) 24 { 25 throw new ArgumentNullException(nameof(keys)); 26 } 27 28 keys.ToList().ForEach(item => _cache.Remove(item)); 29 }
# 获取缓存
1 ///2 /// 获取缓存 3 /// 4 /// 缓存Key 5 ///6 public T Get (string key) where T : class 7 { 8 if (key == null) 9 { 10 throw new ArgumentNullException(nameof(key)); 11 } 12 return _cache.Get(key) as T; 13 } 14 /// 15 /// 获取缓存 16 /// 17 /// 缓存Key 18 ///19 public object Get(string key) 20 { 21 if (key == null) 22 { 23 throw new ArgumentNullException(nameof(key)); 24 } 25 return _cache.Get(key); 26 } 27 /// 28 /// 获取缓存集合 29 /// 30 /// 缓存Key集合 31 ///32 public IDictionary GetAll(IEnumerable keys) 33 { 34 if (keys == null) 35 { 36 throw new ArgumentNullException(nameof(keys)); 37 } 38 39 var dict = new Dictionary (); 40 41 keys.ToList().ForEach(item => dict.Add(item, _cache.Get(item))); 42 43 return dict; 44 }
# 修改缓存
1 ///2 /// 修改缓存 3 /// 4 /// 缓存Key 5 /// 新的缓存Value 6 ///7 public bool Replace(string key, object value) 8 { 9 if (key == null) 10 { 11 throw new ArgumentNullException(nameof(key)); 12 } 13 if (value == null) 14 { 15 throw new ArgumentNullException(nameof(value)); 16 } 17 if (Exists(key)) 18 if (!Remove(key)) return false; 19 20 return Add(key, value); 21 22 } 23 /// 24 /// 修改缓存 25 /// 26 /// 缓存Key 27 /// 新的缓存Value 28 /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) 29 /// 绝对过期时长 30 ///31 public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) 32 { 33 if (key == null) 34 { 35 throw new ArgumentNullException(nameof(key)); 36 } 37 if (value == null) 38 { 39 throw new ArgumentNullException(nameof(value)); 40 } 41 if (Exists(key)) 42 if (!Remove(key)) return false; 43 44 return Add(key, value, expiresSliding, expiressAbsoulte); 45 } 46 /// 47 /// 修改缓存 48 /// 49 /// 缓存Key 50 /// 新的缓存Value 51 /// 缓存时长 52 /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) 53 ///54 public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false) 55 { 56 if (key == null) 57 { 58 throw new ArgumentNullException(nameof(key)); 59 } 60 if (value == null) 61 { 62 throw new ArgumentNullException(nameof(value)); 63 } 64 if (Exists(key)) 65 if (!Remove(key)) return false; 66 67 return Add(key, value, expiresIn, isSliding); 68 }
最后 释放:
public void Dispose()
{
if (_cache != null)
_cache.Dispose();
GC.SuppressFinalize(this);
}
Redis一般都是运行的Liunx的,我们在 【(第十章)】发布项目到 Linux 上运行 Core 项目 中介绍了,如何在Linux上开发运行Core项目,当然,我相信,很多朋友还是在 Windows 上做开发、测试的,这里给大家一个windows 上的Redis和管理软件,如果没有或者不知道怎么找的朋友可以下载下来,在windows上测试 Redis :连接可能失效 百度网盘 提取码:uglb 百度网盘 提取码:gl0e
安装第一个后,启动Redis服务就行了,管理软件的界面也很简洁
我们先来看我们的 RedisCacheService:
为了统一管理和切换使用,我们的 RedisCacheService 同样实现接口 ICacheService
public class RedisCacheService : ICacheService { }
同样,我们通过构造器注入:
protected IDatabase _cache;
private ConnectionMultiplexer _connection;
private readonly string _instance;
public RedisCacheService(RedisCacheOptions options, int database = 0)
{
_connection = ConnectionMultiplexer.Connect(options.Configuration);
_cache = _connection.GetDatabase(database);
_instance = options.InstanceName;
}
说明一下:我们需要添加一个Redis包:Microsoft.Extensions.Caching.Redis,这是官方的,但是不知道是我程序的原因还是什么原因,总是还原失败,命令强行还原包也不行,所以 我用的是移植的包: Microsoft.Extensions.Caching.Redis.Core,如果你们可以,最好还是用官方的包。
这里我们写了个方法,来组合Key值和实例名,就是Key值转为 实例名+Key
public string GetKeyForRedis(string key)
{
return _instance + key;
}
# 验证缓存项是否存在
1 ///2 /// 验证缓存项是否存在 3 /// 4 /// 缓存Key 5 ///6 public bool Exists(string key) 7 { 8 if (key == null) 9 { 10 throw new ArgumentNullException(nameof(key)); 11 } 12 return _cache.KeyExists(GetKeyForRedis(key)); 13 }
# 添加缓存
注意:我翻阅了很多资料,没有找到Redis支持滑动和绝对过期,但是都是继承的统一接口,所以这里添加方法 滑动过期时没有用的。
1 ///2 /// 添加缓存 3 /// 4 /// 缓存Key 5 /// 缓存Value 6 ///7 public bool Add(string key, object value) 8 { 9 if (key == null) 10 { 11 throw new ArgumentNullException(nameof(key)); 12 } 13 return _cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value))); 14 } 15 /// 16 /// 添加缓存 17 /// 18 /// 缓存Key 19 /// 缓存Value 20 /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间,Redis中无效) 21 /// 绝对过期时长 22 ///23 public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) 24 { 25 if (key == null) 26 { 27 throw new ArgumentNullException(nameof(key)); 28 } 29 return _cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)),expiressAbsoulte); 30 } 31 /// 32 /// 添加缓存 33 /// 34 /// 缓存Key 35 /// 缓存Value 36 /// 缓存时长 37 /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间,Redis中无效) 38 ///39 public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false) 40 { 41 if (key == null) 42 { 43 throw new ArgumentNullException(nameof(key)); 44 } 45 46 47 return _cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)), expiresIn); 48 }
# 删除缓存
1 ///2 /// 删除缓存 3 /// 4 /// 缓存Key 5 ///6 public bool Remove(string key) 7 { 8 if (key == null) 9 { 10 throw new ArgumentNullException(nameof(key)); 11 } 12 return _cache.KeyDelete(GetKeyForRedis(key)); 13 } 14 /// 15 /// 批量删除缓存 16 /// 17 /// 缓存Key集合 18 ///19 public void RemoveAll(IEnumerable keys) 20 { 21 if (keys == null) 22 { 23 throw new ArgumentNullException(nameof(keys)); 24 } 25 26 keys.ToList().ForEach(item => Remove(item)); 27 }
# 获取缓存
1 ///2 /// 获取缓存 3 /// 4 /// 缓存Key 5 ///6 public T Get (string key) where T : class 7 { 8 if (key == null) 9 { 10 throw new ArgumentNullException(nameof(key)); 11 } 12 13 var value = _cache.StringGet(GetKeyForRedis(key)); 14 15 if (!value.HasValue) 16 { 17 return default(T); 18 } 19 20 return JsonConvert.DeserializeObject (value); 21 } 22 /// 23 /// 获取缓存 24 /// 25 /// 缓存Key 26 ///27 public object Get(string key) 28 { 29 if (key == null) 30 { 31 throw new ArgumentNullException(nameof(key)); 32 } 33 34 var value = _cache.StringGet(GetKeyForRedis(key)); 35 36 if(!value.HasValue) 37 { 38 return null; 39 } 40 /// 41 /// 获取缓存集合 42 /// 43 /// 缓存Key集合 44 ///45 public IDictionary GetAll(IEnumerable keys) 46 { 47 if (keys == null) 48 { 49 throw new ArgumentNullException(nameof(keys)); 50 } 51 var dict = new Dictionary (); 52 53 keys.ToList().ForEach(item => dict.Add(item, Get(GetKeyForRedis(item)))); 54 55 return dict; 56 } 57 58 return JsonConvert.DeserializeObject(value); 59 }
# 修改缓存
1 ///2 /// 修改缓存 3 /// 4 /// 缓存Key 5 /// 新的缓存Value 6 ///7 public bool Replace(string key, object value) 8 { 9 if (key == null) 10 { 11 throw new ArgumentNullException(nameof(key)); 12 } 13 14 if(Exists(key)) 15 if (!Remove(key)) 16 return false; 17 18 return Add(key, value); 19 20 } 21 /// 22 /// 修改缓存 23 /// 24 /// 缓存Key 25 /// 新的缓存Value 26 /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) 27 /// 绝对过期时长 28 ///29 public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) 30 { 31 if (key == null) 32 { 33 throw new ArgumentNullException(nameof(key)); 34 } 35 36 if (Exists(key)) 37 if (!Remove(key)) 38 return false; 39 40 return Add(key, value, expiresSliding, expiressAbsoulte); 41 } 42 /// 43 /// 修改缓存 44 /// 45 /// 缓存Key 46 /// 新的缓存Value 47 /// 缓存时长 48 /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) 49 ///50 public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false) 51 { 52 if (key == null) 53 { 54 throw new ArgumentNullException(nameof(key)); 55 } 56 57 if (Exists(key)) 58 if (!Remove(key)) return false; 59 60 return Add(key, value, expiresIn, isSliding); 61 }
同样,释放:
public void Dispose()
{
if (_connection != null)
_connection.Dispose();
GC.SuppressFinalize(this);
}
我们在 【(第八章)】读取配置文件(二) 读取自定义配置文件 中讲到了如何读取自定义配置文件,同样,我们把缓存的配置 也放在 我们的自定义配置文件siteconfig.json中:
我们写一个类,来获取配置几个配置:
CacheProvider: _isUseRedis --- 是否使用Redis
_connectionString --- Redis连接
_instanceName ---Redis实例名称
在 Startup.cs 的 ConfigureServices(IServiceCollection services) 中:
首先添加:services.AddMemoryCache();
判断是否使用Redis,如果不使用 Redis就默认使用 MemoryCache:
if (_cacheProvider._isUseRedis)
{
//Use Redis
services.AddSingleton(typeof(ICacheService), new RedisCacheService(new RedisCacheOptions
{
Configuration = _cacheProvider._connectionString,
InstanceName = _cacheProvider._instanceName
},0));
}
else
{
//Use MemoryCache
services.AddSingleton
{
var cache = new MemoryCache(new MemoryCacheOptions());
return cache;
});
services.AddSingleton
}