九、.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是别名,可以任意起。IpRedis的服务端地址,例如安装本地,就是127.0.0.1,端口号Port默认是6379,密码可以通过Redis安装的根目录下的配置文件进行设置,Timeout是连接的超时时间,Db是使用RedisDB区,一般RedisDB区默认是015。注意:此处的配置使用的是数组,用于将来进行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;
            }

        }
View Code

 

然后,新建一个方法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;
        }
View Code

 

在构造函数里面,进行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();
    }
View Code

接口实现部分的整体源码:

  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));
        }

    }
View Code

 

由于时间关系,就不一一列举各自的功能了,各位大佬们可以自行尝试。

最后,说个小窍门:Key值如果使用冒号,在客户端上面查看就会自动变成分层结构。举个例子,改写控制器,原本设置的Test这个Key,改写为Test:Wesky:

 

 

然后,启动程序,让他执行一下,用于生成一条记录,例如此处我写入:Hello Key’s Rules:

 

 

由此可见,Key值分层显示了。在一些场合下,可以使用冒号来分隔开不同层级的Key,以便于在客户端查看。

至此,结束,欢迎打赏、评论和点赞。

版权所有,转载请注明出处:https://www.cnblogs.com/weskynet/p/14847526.html

备注:如果有需要Redis、以及Redis安装包的,以及安装教程,可以加以下的QQ群进行获取和咨询。

posted @ 2021-06-03 22:55  WeskyNet  阅读(5614)  评论(8编辑  收藏  举报