九、.net core(.NET 6)添加通用的Redis功能

简介: .net core 编写通用的Redis功能在 Package项目里面,添加包:StackExchange.Redis:

 

.net core 编写通用的Redis功能


Package项目里面,添加包:StackExchange.Redis:


1995789-20210603223326261-335695793.png


Common工具文件夹下,新建 Wsk.Core.Redis类库项目,并新建 RedisManage 类和对应接口 IRedisManage,如下图。然后,在该项目里面,引用共用包项目Wsk.Core.Package,用以使用Redis有关功能。


1995789-20210603223338041-556822621.png


RedisManage类里面,新增几个用于连接Redis配置的全局变量,以及一个构造函数:


1995789-20210603223359999-1768629060.png


在配置文件里面,新建Redis的有关配置信息:


1995789-20210603223420157-1459689543.png


配置的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安装目录下的配置文件局部一览:


1995789-20210603223535693-1870335700.png


如果打算修改该配置文件来实现修改有关的配置信息,但是没有效果,注意在windows服务里面把redis服务进行重新启动。如果还不行,就把另外一个conf配置文件也做同样的操作,然后再重启redis服务。

 

接着,在解决方案下,新建一个文件夹,叫DataEntities,该文件夹当做将来存放各种实体类或有关项目的目录。现在咱们在该新建的文件夹下,新建一个类库项目:Wsk.Core.Entity,然后新建一个实体类,叫RedisConfig,用于读取到配置文件的Redis信息进行赋值使用:

 

1995789-20210603223733365-1684524059.png

 

回到Redis类库项目,在RedisManage类里面,添加一个方法ReadRedisSetting,用于读取该配置信息,并赋值给ConfigurationOptions类:

1995789-20210603223750967-1215896057.png

 

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


1995789-20210603224011918-249522848.png


方法代码:


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连接的实现:


1995789-20210603224304723-1529136744.png

 

现在,做个简单的测试,新建一个Set方法和一个GetValue方法,用于测试效果:

1995789-20210603224324387-1366725951.png


IRedisMagane接口里面,添加以上有关的接口方法:


1995789-20210603224347864-1024988556.png


现在转到启动项目上,启动项目新增对Wsk.Core.Redis项目的引用,并且在WskService类下面,新增对刚刚新增的Redis管理类的依赖注入的注册:


1995789-20210603224403965-1794011055.png


现在,在控制器里面,添加有关构造函数的依赖注入,然后做个实践,验证下是否成功。

先改写控制器内容,先设置一对key/value,然后进行读取并返回:


1995789-20210603224422401-959744571.png

 

启动项目,输入Hello Redis! ,然后查看返回对应的内容:

 

1995789-20210603224447142-385945293.png

 

我们打开Redis管理客户端看看,是不是可以看见有这个值:


1995789-20210603224505767-63457952.png


因为我们配置的是Db = 3,所以在Db3这个地方,可以看见我们的Key,点击Tesk,即可在右边窗口看见对应的内容。说明Redis操作成功。


最后,咱们对Redis管理类进行一些其他功能的添加,以及接口方法的添加,用于完善它的功能链,包括移除、读取实体数据、清空、异步操作等。以下截图为对应的接口方法展示:

1995789-20210603224531402-989283873.png


接口部分源码:


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:


1995789-20210603224845307-2104645993.png

 

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


1995789-20210603224900041-622957771.png

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


目录
相关文章
|
7月前
|
开发框架 .NET C#
ASP.NET Core Blazor 路由配置和导航
大家好,我是码农刚子。本文系统介绍Blazor单页应用的路由机制,涵盖基础配置、路由参数、编程式导航及高级功能。通过@page指令定义路由,支持参数约束、可选参数与通配符捕获,结合NavigationManager实现页面跳转与参数传递,并演示用户管理、产品展示等典型场景,全面掌握Blazor路由从入门到实战的完整方案。
622 6
|
Shell 网络安全 C#
一款 .NET 开源、功能强大的远程连接管理工具,支持 RDP、VNC、SSH 等多种主流协议!
一款 .NET 开源、功能强大的远程连接管理工具,支持 RDP、VNC、SSH 等多种主流协议!
477 4
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
680 5
|
缓存 开发框架 .NET
一个功能丰富的 .NET 工具库 XiHan.Framework.Utils
XiHan.Framework.Utils 是一个功能全面的 .NET 工具库,包含字符串处理、集合扩展、加密解密、分布式 ID、文件操作、缓存、线程、国际化等模块。设计上注重高内聚、低耦合,适用于各类 .NET 应用开发。支持 AES 加密、树形结构转换、分页过滤、日志输出等功能,提供简单易用的 API。可通过 NuGet 快速安装,源码开放,采用 MIT 协议。
424 56
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
369 32
|
9月前
|
存储 NoSQL Redis
采用Redis的Bitmaps实现类似Github连续提交状态的功能。
在现实世界的应用开发中,实现类似于Github提交跟踪系统时,还可能需要考虑用户时区、闰年等日期相关的边界条件,以及辅助数据的存储和查询优化,例如对活跃用户的即时查询和统计等。不过这些都可以在Bitmaps的基础功能之上通过额外的代码逻辑来实现。
201 0
|
存储 监控 NoSQL
使用Redis实现延迟消息发送功能
使用 Redis 的密码认证功能,为实例设置密码以防止未授权访问。为消息提供适当加密,确保消息内容在网络传输过程中不被窃取或篡改。
432 16
|
NoSQL Redis 数据库
Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
通过本文的介绍,我们详细讲解了 Lua 脚本在 Redis 中的作用、`eval` 命令的使用方法以及 `redis.call` 和 `redis.pcall` 的区别和用法。通过合理使用 Lua 脚本,可以实现复杂的业务逻辑,确保操作的原子性,并减少网络开销,从而提高系统的性能和可靠性。
1062 13
|
Linux API C#
基于 .NET 开发的多功能流媒体管理控制平台
基于 .NET 开发的多功能流媒体管理控制平台
306 9
|
网络协议 C#
3款.NET开源、功能强大的通讯调试工具,效率提升利器!
3款.NET开源、功能强大的通讯调试工具,效率提升利器!
284 10