九、.net core(.NET 6)添加通用的Redis功能
.net core 编写通用的Redis功能
在 Package项目里面,添加包:StackExchange.Redis:
在Common工具文件夹下,新建 Wsk.Core.Redis类库项目,并新建 RedisManage 类和对应接口 IRedisManage,如下图。然后,在该项目里面,引用共用包项目Wsk.Core.Package,用以使用Redis有关功能。
在RedisManage类里面,新增几个用于连接Redis配置的全局变量,以及一个构造函数:
在配置文件里面,新建Redis的有关配置信息:
配置的Json文本:
"Redis": [ { "Name": "Wesky", "Ip": "127.0.0.1", "Port": 6379, "Password": "wesky123", "Timeout": 30, "Db": 3 } ]
其中,Name是别名,可以任意起。Ip是Redis的服务端地址,例如安装本地,就是127.0.0.1,端口号Port默认是6379,密码可以通过Redis安装的根目录下的配置文件进行设置,Timeout是连接的超时时间,Db是使用Redis的DB区,一般Redis的DB区默认是0到15。注意:此处的配置使用的是数组,用于将来进行Redis分布式操作的可拓展。
看下redis安装目录下的配置文件局部一览:
如果打算修改该配置文件来实现修改有关的配置信息,但是没有效果,注意在windows服务里面把redis服务进行重新启动。如果还不行,就把另外一个conf配置文件也做同样的操作,然后再重启redis服务。
接着,在解决方案下,新建一个文件夹,叫DataEntities,该文件夹当做将来存放各种实体类或有关项目的目录。现在咱们在该新建的文件夹下,新建一个类库项目:Wsk.Core.Entity,然后新建一个实体类,叫RedisConfig,用于读取到配置文件的Redis信息进行赋值使用:
回到Redis类库项目,在RedisManage类里面,添加一个方法ReadRedisSetting,用于读取该配置信息,并赋值给ConfigurationOptions类:
ReadRedisSetting代码:
private ConfigurationOptions ReadRedisSetting() { try { List<RedisConfig> config = AppHelper.ReadAppSettings<RedisConfig>(new string[] { "Redis" }); // 读取Redis配置信息 if (config.Any()) { ConfigurationOptions options = new ConfigurationOptions { EndPoints = { { config.FirstOrDefault().Ip, config.FirstOrDefault().Port } }, ClientName = config.FirstOrDefault().Name, Password = config.FirstOrDefault().Password, ConnectTimeout = config.FirstOrDefault().Timeout, DefaultDatabase = config.FirstOrDefault().Db, }; return options; } return null; } catch(Exception ex) { _logger.LogError($"获取Redis配置信息失败:{ex.Message}"); return null; } }
然后,新建一个方法ConnectionRedis,用于连接Redis:
方法代码:
private ConnectionMultiplexer ConnectionRedis() { if (this._redisConnection != null && this._redisConnection.IsConnected) { return this._redisConnection; // 已有连接,直接使用 } lock (_redisConnectionLock) { if (this._redisConnection != null) { this._redisConnection.Dispose(); // 释放,重连 } try { this._redisConnection = ConnectionMultiplexer.Connect(_configOptions); } catch (Exception ex) { _logger.LogError($"Redis服务启动失败:{ex.Message}"); } } return this._redisConnection; }
在构造函数里面,进行Redis连接的实现:
现在,做个简单的测试,新建一个Set方法和一个GetValue方法,用于测试效果:
在IRedisMagane接口里面,添加以上有关的接口方法:
现在转到启动项目上,启动项目新增对Wsk.Core.Redis项目的引用,并且在WskService类下面,新增对刚刚新增的Redis管理类的依赖注入的注册:
现在,在控制器里面,添加有关构造函数的依赖注入,然后做个实践,验证下是否成功。
先改写控制器内容,先设置一对key/value,然后进行读取并返回:
启动项目,输入Hello Redis! ,然后查看返回对应的内容:
我们打开Redis管理客户端看看,是不是可以看见有这个值:
因为我们配置的是Db = 3,所以在Db3这个地方,可以看见我们的Key,点击Tesk,即可在右边窗口看见对应的内容。说明Redis操作成功。
最后,咱们对Redis管理类进行一些其他功能的添加,以及接口方法的添加,用于完善它的功能链,包括移除、读取实体数据、清空、异步操作等。以下截图为对应的接口方法展示:
接口部分源码:
public interface IRedisManage { /// <summary> /// 设置一个 键值对 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <param name="ts"></param> void Set(string key, object value, TimeSpan ts); /// <summary> /// //获取 Reids 缓存值 /// </summary> /// <param name="key"></param> /// <returns></returns> string GetValue(string key); /// <summary> /// 获取序列化值 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="key"></param> /// <returns></returns> TEntity Get<TEntity>(string key); /// <summary> /// 判断Key是否存在 /// </summary> /// <param name="key"></param> /// <returns></returns> bool Get(string key); /// <summary> /// 移除某个Key和值 /// </summary> /// <param name="key"></param> void Remove(string key); /// <summary> /// 清空Redis /// </summary> void Clear(); /// <summary> /// 异步获取 Reids 缓存值 /// </summary> /// <param name="key"></param> /// <returns></returns> Task<string> GetValueAsync(string key); /// <summary> /// 异步获取序列化值 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="key"></param> /// <returns></returns> Task<TEntity> GetAsync<TEntity>(string key); Task SetAsync(string key, object value, TimeSpan cacheTime); Task<bool> GetAsync(string key); /// <summary> /// 异步移除指定的key /// </summary> /// <param name="key"></param> /// <returns></returns> Task RemoveAsync(string key); /// <summary> /// 异步移除模糊查询到的key /// </summary> /// <param name="key"></param> /// <returns></returns> Task RemoveByKey(string key); /// <summary> /// 异步全部清空 /// </summary> /// <returns></returns> Task ClearAsync(); }
接口实现部分的整体源码:
public class RedisManage : IRedisManage { public volatile ConnectionMultiplexer _redisConnection; private readonly object _redisConnectionLock = new object(); private readonly ConfigurationOptions _configOptions; private readonly ILogger<RedisManage> _logger; public RedisManage(ILogger<RedisManage> logger) { _logger = logger; ConfigurationOptions options = ReadRedisSetting(); if (options == null) { _logger.LogError("Redis数据库配置有误"); } this._configOptions = options; this._redisConnection = ConnectionRedis(); } private ConfigurationOptions ReadRedisSetting() { try { List<RedisConfig> config = AppHelper.ReadAppSettings<RedisConfig>(new string[] { "Redis" }); // 读取Redis配置信息 if (config.Any()) { ConfigurationOptions options = new ConfigurationOptions { EndPoints = { { config.FirstOrDefault().Ip, config.FirstOrDefault().Port } }, ClientName = config.FirstOrDefault().Name, Password = config.FirstOrDefault().Password, ConnectTimeout = config.FirstOrDefault().Timeout, DefaultDatabase = config.FirstOrDefault().Db, }; return options; } return null; } catch(Exception ex) { _logger.LogError($"获取Redis配置信息失败:{ex.Message}"); return null; } } private ConnectionMultiplexer ConnectionRedis() { if (this._redisConnection != null && this._redisConnection.IsConnected) { return this._redisConnection; // 已有连接,直接使用 } lock (_redisConnectionLock) { if (this._redisConnection != null) { this._redisConnection.Dispose(); // 释放,重连 } try { this._redisConnection = ConnectionMultiplexer.Connect(_configOptions); } catch (Exception ex) { _logger.LogError($"Redis服务启动失败:{ex.Message}"); } } return this._redisConnection; } public string GetValue(string key) { return _redisConnection.GetDatabase().StringGet(key); } public void Set(string key, object value, TimeSpan ts) { if (value != null) { _redisConnection.GetDatabase().StringSet(key, JsonConvert.SerializeObject(value), ts); } } public void Clear() { foreach (var endPoint in this.ConnectionRedis().GetEndPoints()) { var server = this.ConnectionRedis().GetServer(endPoint); foreach (var key in server.Keys()) { _redisConnection.GetDatabase().KeyDelete(key); } } } public bool Get(string key) { return _redisConnection.GetDatabase().KeyExists(key); } public TEntity Get<TEntity>(string key) { var value = _redisConnection.GetDatabase().StringGet(key); if (value.HasValue) { //需要用的反序列化,将Redis存储的Byte[],进行反序列化 return JsonConvert.DeserializeObject<TEntity>(value); } else { return default(TEntity); } } public void Remove(string key) { _redisConnection.GetDatabase().KeyDelete(key); } public bool SetValue(string key, byte[] value) { return _redisConnection.GetDatabase().StringSet(key, value, TimeSpan.FromSeconds(120)); } public async Task ClearAsync() { foreach (var endPoint in this.ConnectionRedis().GetEndPoints()) { var server = this.ConnectionRedis().GetServer(endPoint); foreach (var key in server.Keys()) { await _redisConnection.GetDatabase().KeyDeleteAsync(key); } } } public async Task<bool> GetAsync(string key) { return await _redisConnection.GetDatabase().KeyExistsAsync(key); } public async Task<string> GetValueAsync(string key) { return await _redisConnection.GetDatabase().StringGetAsync(key); } public async Task<TEntity> GetAsync<TEntity>(string key) { var value = await _redisConnection.GetDatabase().StringGetAsync(key); if (value.HasValue) { return JsonConvert.DeserializeObject<TEntity>(value); } else { return default; } } public async Task RemoveAsync(string key) { await _redisConnection.GetDatabase().KeyDeleteAsync(key); } public async Task RemoveByKey(string key) { var redisResult = await _redisConnection.GetDatabase().ScriptEvaluateAsync(LuaScript.Prepare( //模糊查询: " local res = redis.call('KEYS', @keypattern) " + " return res "), new { @keypattern = key }); if (!redisResult.IsNull) { var keys = (string[])redisResult; foreach (var k in keys) _redisConnection.GetDatabase().KeyDelete(k); } } public async Task SetAsync(string key, object value, TimeSpan cacheTime) { if (value != null) { await _redisConnection.GetDatabase().StringSetAsync(key, JsonConvert.SerializeObject(value), cacheTime); } } public async Task<bool> SetValueAsync(string key, byte[] value) { return await _redisConnection.GetDatabase().StringSetAsync(key, value, TimeSpan.FromSeconds(120)); } }
由于时间关系,就不一一列举各自的功能了,各位大佬们可以自行尝试。
最后,说个小窍门:Key值如果使用冒号,在客户端上面查看就会自动变成分层结构。举个例子,改写控制器,原本设置的Test这个Key,改写为Test:Wesky:
然后,启动程序,让他执行一下,用于生成一条记录,例如此处我写入:Hello Key’s Rules:
由此可见,Key值分层显示了。在一些场合下,可以使用冒号来分隔开不同层级的Key,以便于在客户端查看。
至此,结束,欢迎打赏、评论和点赞。
版权所有,转载请注明出处:https://www.cnblogs.com/weskynet/p/14847526.html
备注:如果有需要Redis、以及Redis安装包的,以及安装教程,可以加以下的QQ群进行获取和咨询。
本文作者:Wesky
微信号:WeskyNet001
公众号:Dotnet Dancer
文章链接:https://www.cnblogs.com/weskynet/p/14847526.html
欢迎扫一扫关注公众号,发现更多其他技术分享