5, by adding cache support
We hope to increase caching support for the project, we chose Redis as cache database.
First of all, we are in Services to add a cache interface class directory ICacheService :
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks;
namespace ChainStoreAPI.Services { public interface ICacheService { /// <summary> /// verify the existence of the cache entry /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> bool Exists(string key);
/// <summary> /// verify the existence of the cache entry (asynchronous) /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> Task<bool> ExistsAsync(string key);
/// <summary> /// add cache /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <returns></returns> bool Add(string key, object value);
/// <summary> /// add the cache (asynchronous) /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <returns></returns> Task<bool> AddAsync(string key, object value);
/// <summary> /// add cache /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <param name="expiressAbsoulte">绝对过期时长</param> /// <returns></returns> bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
/// <summary> /// 添加缓存(异步方式) /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <param name="expiressAbsoulte">绝对过期时长</param> /// <returns></returns> Task<bool> AddAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
/// <summary> /// 添加缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <param name="expiresIn">缓存时长</param> /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <returns></returns> bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false);
/// <summary> /// 添加缓存(异步方式) /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <param name="expiresIn">缓存时长</param> /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <returns></returns> Task<bool> AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false);
/// <summary> /// 删除缓存 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> bool Remove(string key);
/// <summary> /// 删除缓存(异步方式) /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> Task<bool> RemoveAsync(string key);
/// <summary> /// 批量删除缓存 /// </summary> /// <param name="key">缓存Key集合</param> /// <returns></returns> void RemoveAll(IEnumerable<string> keys);
/// <summary> /// 批量删除缓存(异步方式) /// </summary> /// <param name="key">缓存Key集合</param> /// <returns></returns> Task RemoveAllAsync(IEnumerable<string> keys);
/// <summary> /// 获取缓存 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> T Get<T>(string key) where T : class;
/// <summary> /// 获取缓存(异步方式) /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> Task<T> GetAsync<T>(string key) where T : class;
/// <summary> /// 获取缓存 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> object Get(string key);
/// <summary> /// 获取缓存(异步方式) /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> Task<object> GetAsync(string key);
/// <summary> /// 获取缓存集合 /// </summary> /// <param name="keys">缓存Key集合</param> /// <returns></returns> IDictionary<string, object> GetAll(IEnumerable<string> keys);
/// <summary> /// 获取缓存集合(异步方式) /// </summary> /// <param name="keys">缓存Key集合</param> /// <returns></returns> Task<IDictionary<string, object>> GetAllAsync(IEnumerable<string> keys);
/// <summary> /// 修改缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">新的缓存Value</param> /// <returns></returns> bool Replace(string key, object value);
/// <summary> /// 修改缓存(异步方式) /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">新的缓存Value</param> /// <returns></returns> Task<bool> ReplaceAsync(string key, object value);
/// <summary> /// 修改缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">新的缓存Value</param> /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <param name="expiressAbsoulte">绝对过期时长</param> /// <returns></returns> bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
/// <summary> /// 修改缓存(异步方式) /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">新的缓存Value</param> /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <param name="expiressAbsoulte">绝对过期时长</param> /// <returns></returns> Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte);
/// <summary> /// 修改缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">新的缓存Value</param> /// <param name="expiresIn">缓存时长</param> /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <returns></returns> bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false);
/// <summary> /// 修改缓存(异步方式) /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">新的缓存Value</param> /// <param name="expiresIn">缓存时长</param> /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <returns></returns> Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false); } } |
然后,在增加实现类之前,先引入Redis的依赖项:
选择Microsoft.Extensions.Caching.Redis,版本选择2.1.2,安装一下。
在Services\Impl目录增加Redis的缓存实现类RedisCacheService:
using Microsoft.Extensions.Caching.Redis; using Newtonsoft.Json; using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
namespace ChainStoreAPI.Services.Impl { public class RedisCacheService : ICacheService { protected IDatabase _cache;
private ConnectionMultiplexer _connection;
private readonly string _instance;
/// <summary> /// 构造函数 /// </summary> /// <param name="options"></param> /// <param name="database"></param> public RedisCacheService(RedisCacheOptions options, int database = 0) { _connection = ConnectionMultiplexer.Connect(options.Configuration); _cache = _connection.GetDatabase(database); _instance = options.InstanceName; }
/// <summary> /// 为Key添加实例名 /// </summary> /// <param name="key"></param> /// <returns></returns> public string GetKeyForRedis(string key) { return _instance + ":" + key; }
#region 验证缓存项是否存在 /// <summary> /// 验证缓存项是否存在 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> public bool Exists(string key) { if (key == null) { throw new ArgumentNullException(nameof(key)); } return _cache.KeyExists(GetKeyForRedis(key)); }
public async Task<bool> ExistsAsync(string key) { bool result = await Task.Run(() => Exists(key)); return result; } #endregion
#region 添加缓存 /// <summary> /// 添加缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <returns></returns> public bool Add(string key, object value) { if (key == null) { throw new ArgumentNullException(nameof(key)); } return _cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value))); }
/// <summary> /// 添加缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间,Redis中无效)</param> /// <param name="expiressAbsoulte">绝对过期时长</param> /// <returns></returns> public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) { if (key == null) { throw new ArgumentNullException(nameof(key)); } return _cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)), expiressAbsoulte); }
/// <summary> /// 添加缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">缓存Value</param> /// <param name="expiresIn">缓存时长</param> /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间,Redis中无效)</param> /// <returns></returns> public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false) { if (key == null) { throw new ArgumentNullException(nameof(key)); }
return _cache.StringSet(GetKeyForRedis(key), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)), expiresIn); }
public async Task<bool> AddAsync(string key, object value) { bool result = await Task.Run(() => Add(key, value)); return result; }
public async Task<bool> AddAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) { bool result = await Task.Run(() => Add(key, value, expiresSliding, expiressAbsoulte)); return result; }
public async Task<bool> AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false) { bool result = await Task.Run(() => Add(key, value, expiresIn, isSliding)); return result; } #endregion
#region 删除缓存 /// <summary> /// 删除缓存 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> public bool Remove(string key) { if (key == null) { throw new ArgumentNullException(nameof(key)); } return _cache.KeyDelete(GetKeyForRedis(key)); }
/// <summary> /// 批量删除缓存 /// </summary> /// <param name="key">缓存Key集合</param> /// <returns></returns> public void RemoveAll(IEnumerable<string> keys) { if (keys == null) { throw new ArgumentNullException(nameof(keys)); }
keys.ToList().ForEach(item => Remove(item)); }
public async Task<bool> RemoveAsync(string key) { bool result = await Task.Run(() => Remove(key)); return result; }
public async Task RemoveAllAsync(IEnumerable<string> keys) { await Task.Run(() => RemoveAll(keys)); } #endregion
#region 获取缓存 /// <summary> /// 获取缓存 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> public T Get<T>(string key) where T : class { if (key == null) { throw new ArgumentNullException(nameof(key)); }
var value = _cache.StringGet(GetKeyForRedis(key)); if (!value.HasValue) { return default(T); }
return JsonConvert.DeserializeObject<T>(value); }
/// <summary> /// 获取缓存 /// </summary> /// <param name="key">缓存Key</param> /// <returns></returns> public object Get(string key) { if (key == null) { throw new ArgumentNullException(nameof(key)); }
var value = _cache.StringGet(GetKeyForRedis(key)); if (!value.HasValue) { return null; }
return JsonConvert.DeserializeObject(value); }
/// <summary> /// 获取缓存集合 /// </summary> /// <param name="keys">缓存Key集合</param> /// <returns></returns> public IDictionary<string, object> GetAll(IEnumerable<string> keys) { if (keys == null) { throw new ArgumentNullException(nameof(keys)); }
var dict = new Dictionary<string, object>(); keys.ToList().ForEach(item => dict.Add(item, Get(GetKeyForRedis(item))));
return dict; }
public async Task<T> GetAsync<T>(string key) where T : class { T result = await Task.Run(() => Get(key)) as T; return result; }
public async Task<object> GetAsync(string key) { object result = await Task.Run(() => Get(key)); return result; }
public async Task<IDictionary<string, object>> GetAllAsync(IEnumerable<string> keys) { IDictionary<string, object> result = await Task.Run(() => GetAll(keys)); return result; } #endregion
#region 修改缓存 /// <summary> /// 修改缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">新的缓存Value</param> /// <returns></returns> public bool Replace(string key, object value) { if (key == null) { throw new ArgumentNullException(nameof(key)); }
if (Exists(key)) if (!Remove(key)) return false;
return Add(key, value); }
/// <summary> /// 修改缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">新的缓存Value</param> /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <param name="expiressAbsoulte">绝对过期时长</param> /// <returns></returns> public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) { if (key == null) { throw new ArgumentNullException(nameof(key)); }
if (Exists(key)) if (!Remove(key)) return false;
return Add(key, value, expiresSliding, expiressAbsoulte); }
/// <summary> /// 修改缓存 /// </summary> /// <param name="key">缓存Key</param> /// <param name="value">新的缓存Value</param> /// <param name="expiresIn">缓存时长</param> /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param> /// <returns></returns> public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false) { if (key == null) { throw new ArgumentNullException(nameof(key)); }
if (Exists(key)) if (!Remove(key)) return false;
return Add(key, value, expiresIn, isSliding); }
public async Task<bool> ReplaceAsync(string key, object value) { bool result = await Task.Run(() => Replace(key, value)); return result; }
public async Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) { bool result = await Task.Run(() => Replace(key, value, expiresSliding, expiressAbsoulte)); return result; }
public async Task<bool> ReplaceAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false) { bool result = await Task.Run(() => Replace(key, value, expiresIn, isSliding)); return result; } #endregion
/// <summary> /// 释放 /// </summary> public void Dispose() { if (_connection != null) _connection.Dispose(); GC.SuppressFinalize(this); } } } |
在配置文件appsettings.json中加入Redis的链接字符串:
"RedisConnectionString": "127.0.0.1:6379" |
然后打开Startup.cs,引入缓存服务类:
当然,现在我们需要安装好Redis并启动:
运行run.bat即可:
我们将控制器TestController.cs重命名为MemberController.cs:
再新增测试控制器,将来我们的测试代码都在这里面实现:
我们只保留Get方法,其他全删除:
修改BaseController,加入缓存支持:
这样,我们就可以在所有继承BaseController的控制器中使用缓存了。
修改MemberController和TestController的构造函数:
下面我们在测试控制器中写代码测试一下缓存的写入和读取:
// GET: api/Test [HttpGet] public ResultInfo Get() { cache.Add("test", "这是一个测试字符串"); string value = cache.Get<string>("test");
return new ResultInfo() { Code = "0", Message = "成功", Data = value }; } |
运行看一下效果:
打开RedisDesktopManager看一下Redis数据库中是否写入: