分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 教程案例

[外包]!采用asp.net core 快速构建小型创业公司后台管理系统(三)

发布时间:2023-09-06 02:23责任编辑:熊小新关键词:暂无标签

接着上一章节继续唠唠

本章主要说一下Redis

  • Redis操作优化

一.基础类的配置工作

  1.我想信许多人(许多neter人)操作redis依然用的是StackExchange.Redis,这个neget包,并没有用国内现在一些大佬们推出了包

  

  RedisOptions主要是redis连接的一个配置类

  实现代码如下:

public class RedisOptions ???{ ???????/// <summary> ???????/// 数据库地址 ???????/// </summary> ???????public string RedisHost { get; set; } ???????/// <summary> ???????/// 数据库用户名 ???????/// </summary> ???????public string RedisName { get; set; } ???????/// <summary> ???????/// 数据库密码 ???????/// </summary> ???????public string RedisPass { get; set; } ???????/// <summary> ???????/// 库 ???????/// </summary> ???????public int RedisIndex { get; set; } ???}

  RedisServiceExtensions,算是redis操作的核心类,主要封装了redis的crud以及sub,pub

public static class RedisServiceExtensions ???{ ???????#region 初始化参数 ???????private static readonly int _DefulatTime = 600; //默认有效期 ???????private static RedisOptions config; ???????private static ConnectionMultiplexer connection; ???????private static IDatabase _db; ???????private static ISubscriber _sub; ???????#endregion ???????public static IServiceCollection AddRedisCacheService( ???????????this IServiceCollection serviceCollection, ???????????Func<RedisOptions, RedisOptions> redisOptions = null ???????????) ???????{ ???????????var _redisOptions = new RedisOptions(); ???????????_redisOptions = redisOptions?.Invoke(_redisOptions) ?? _redisOptions; ???????????config = _redisOptions; ???????????connection = ConnectionMultiplexer.Connect(GetSystemOptions()); ???????????_db = connection.GetDatabase(config.RedisIndex); ???????????_sub = connection.GetSubscriber(); ???????????return serviceCollection; ???????} ???????????????#region 系统配置 ???????/// <summary> ???????/// 获取系统配置 ???????/// </summary> ???????/// <returns></returns> ???????private static ConfigurationOptions GetSystemOptions() ???????{ ???????????var options = new ConfigurationOptions ???????????{ ???????????????AbortOnConnectFail = false, ???????????????AllowAdmin = true, ???????????????ConnectRetry = 10, ???????????????ConnectTimeout = 5000, ???????????????KeepAlive = 30, ???????????????SyncTimeout = 5000, ???????????????EndPoints = { config.RedisHost }, ???????????????ServiceName = config.RedisName, ???????????}; ???????????if (!string.IsNullOrWhiteSpace(config.RedisPass)) ???????????{ ???????????????options.Password = config.RedisPass; ???????????} ???????????return options; ???????} ???????#endregion ???????//============ ???????#region 获取缓存 ???????/// <summary> ???????/// 读取缓存 ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <returns>数据类型/NULL</returns> ???????public static object Get(string key) ???????{ ???????????return Get<object>(key); ???????} ???????/// <summary> ???????/// 读取缓存 ???????/// </summary> ???????/// <typeparam name="T">泛型</typeparam> ???????/// <param name="key">键</param> ???????/// <returns>数据类型/NULL</returns> ???????public static T Get<T>(string key) ???????{ ???????????var value = _db.StringGet(key); ???????????return (value.IsNull ? default(T) : JsonTo<T>(value).Value); ???????} ???????#endregion ???????#region 异步获取缓存 ???????/// <summary> ???????/// 异步读取缓存 ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <returns>object/NULL</returns> ???????public static async Task<object> GetAsync(string key) ???????{ ???????????return await GetAsync<object>(key); ???????} ???????/// <summary> ???????/// 异步读取缓存 ???????/// </summary> ???????/// <typeparam name="T">泛型</typeparam> ???????/// <param name="key">键</param> ???????/// <returns>数据类型/NULL</returns> ???????public static async Task<T> GetAsync<T>(string key) ???????{ ???????????var value = await _db.StringGetAsync(key); ???????????return (value.IsNull ? default(T) : JsonTo<T>(value).Value); ???????} ???????#endregion ???????#region 同步转异步添加[I/O密集] ???????/// <summary> ???????/// 添加缓存 ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="never">是否永久保存[true:是,false:保存10分钟]</param> ???????public static bool Insert(string key, object data, bool never = false) ???????{ ???????????return InsertAsync(key, data, never).Result; ???????} ???????/// <summary> ???????/// 添加缓存 ???????/// </summary> ???????/// <typeparam name="T">泛型</typeparam> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="never">是否永久保存[true:是,false:保存10分钟]</param> ???????/// <returns>添加结果</returns> ???????public static bool Insert<T>(string key, T data, bool never = false) ???????{ ???????????return InsertAsync<T>(key, data, never).Result; ???????} ???????/// <summary> ???????/// 添加缓存 ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="time">保存时间[单位:秒]</param> ???????/// <returns>添加结果</returns> ???????public static bool Insert(string key, object data, int time) ???????{ ???????????return InsertAsync(key, data, time).Result; ???????} ???????/// <summary> ???????/// 添加缓存 ???????/// </summary> ???????/// <typeparam name="T">泛型</typeparam> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="time">保存时间[单位:秒]</param> ???????/// <returns>添加结果</returns> ???????public static bool Insert<T>(string key, T data, int time) ???????{ ???????????return InsertAsync<T>(key, data, time).Result; ???????} ???????/// <summary> ???????/// 添加缓存 ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="cachetime">缓存时间</param> ???????/// <returns>添加结果</returns> ???????public static bool Insert(string key, object data, DateTime cachetime) ???????{ ???????????return InsertAsync(key, data, cachetime).Result; ???????} ???????/// <summary> ???????/// 添加缓存 ???????/// </summary> ???????/// <typeparam name="T">泛型</typeparam> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="cachetime">缓存时间</param> ???????/// <returns>添加结果</returns> ???????public static bool Insert<T>(string key, T data, DateTime cachetime) ???????{ ???????????return InsertAsync<T>(key, data, cachetime).Result; ???????} ???????#endregion ???????#region 异步添加 ???????/// <summary> ???????/// 添加缓存[异步] ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="never">是否永久保存[true:是,false:保存10分钟]</param> ???????/// <returns>添加结果</returns> ???????public static async Task<bool> InsertAsync(string key, object data, bool never = false) ???????{ ???????????return await _db.StringSetAsync(key, ToJson(data), (never ? null : new TimeSpan?(TimeSpan.FromSeconds(_DefulatTime)))); ???????} ???????/// <summary> ???????/// 添加缓存[异步] ???????/// </summary> ???????/// <typeparam name="T">泛型</typeparam> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="never">是否永久保存[true:是,false:保存10分钟]</param> ???????/// <returns>添加结果</returns> ???????public static async Task<bool> InsertAsync<T>(string key, T data, bool never = false) ???????{ ???????????return await _db.StringSetAsync(key, ToJson<T>(data), (never ? null : new TimeSpan?(TimeSpan.FromSeconds(_DefulatTime)))); ???????} ???????/// <summary> ???????/// 添加缓存[异步] ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="time">保存时间[单位:秒]</param> ???????/// <returns>添加结果</returns> ???????public static async Task<bool> InsertAsync(string key, object data, int time) ???????{ ???????????return await _db.StringSetAsync(key, ToJson(data), new TimeSpan?(TimeSpan.FromSeconds(time))); ???????} ???????/// <summary> ???????/// 添加缓存[异步] ???????/// </summary> ???????/// <typeparam name="T">泛型</typeparam> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="time">保存时间[单位:秒]</param> ???????/// <returns>添加结果</returns> ???????public static async Task<bool> InsertAsync<T>(string key, T data, int time) ???????{ ???????????return await _db.StringSetAsync(key, ToJson<T>(data), new TimeSpan?(TimeSpan.FromSeconds(time))); ???????} ???????/// <summary> ???????/// 添加缓存[异步] ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="cachetime">缓存时间</param> ???????/// <returns>添加结果</returns> ???????public static async Task<bool> InsertAsync(string key, object data, DateTime cachetime) ???????{ ???????????return await _db.StringSetAsync(key, ToJson(data), new TimeSpan?(cachetime - DateTime.Now)); ???????} ???????/// <summary> ???????/// 添加缓存[异步] ???????/// </summary> ???????/// <typeparam name="T">泛型</typeparam> ???????/// <param name="key">键</param> ???????/// <param name="data">数据</param> ???????/// <param name="cachetime">缓存时间</param> ???????/// <returns>添加结果</returns> ???????public static async Task<bool> InsertAsync<T>(string key, T data, DateTime cachetime) ???????{ ???????????return await _db.StringSetAsync(key, ToJson<T>(data), new TimeSpan?(cachetime - DateTime.Now)); ???????} ???????#endregion ???????#region 验证缓存 ???????/// <summary> ???????/// 验证缓存是否存在 ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <returns>验证结果</returns> ???????public static bool Exists(string key) ???????{ ???????????return _db.KeyExists(key); ???????} ???????#endregion ???????#region 异步验证缓存 ???????/// <summary> ???????/// 验证缓存是否存在 ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <returns>验证结果</returns> ???????public static async Task<bool> ExistsAsync(string key) ???????{ ???????????return await _db.KeyExistsAsync(key); ???????} ???????#endregion ???????#region 移除缓存 ???????/// <summary> ???????/// 移除缓存 ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <returns>移除结果</returns> ???????public static bool Remove(string key) ???????{ ???????????return _db.KeyDelete(key); ???????} ???????#endregion ???????#region 异步移除缓存 ???????/// <summary> ???????/// 移除缓存 ???????/// </summary> ???????/// <param name="key">键</param> ???????/// <returns>移除结果</returns> ???????public static async Task<bool> RemoveAsync(string key) ???????{ ???????????return await _db.KeyDeleteAsync(key); ???????} ???????#endregion ???????#region 队列发布 ???????/// <summary> ???????/// 队列发布 ???????/// </summary> ???????/// <param name="Key">通道名</param> ???????/// <param name="data">数据</param> ???????/// <returns>是否有消费者接收</returns> ???????public static bool Publish(Models.RedisChannels Key, object data) ???????{ ???????????return _sub.Publish(Key.ToString(), ToJson(data)) > 0 ? true : false; ???????} ???????#endregion ???????#region 队列接收 ???????/// <summary> ???????/// 注册通道并执行对应方法 ???????/// </summary> ???????/// <typeparam name="T">数据类型</typeparam> ???????/// <param name="Key">通道名</param> ???????/// <param name="doSub">方法</param> ???????public static void Subscribe<T>(Models.RedisChannels Key, DoSub doSub) where T : class ???????{ ???????????var _subscribe = connection.GetSubscriber(); ???????????_subscribe.Subscribe(Key.ToString(), delegate (RedisChannel channel, RedisValue message) ???????????{ ???????????????T t = Recieve<T>(message); ???????????????doSub(t); ???????????}); ???????} ???????#endregion ???????#region 退订队列通道 ???????/// <summary> ???????/// 退订队列通道 ???????/// </summary> ???????/// <param name="Key">通道名</param> ???????public static void UnSubscribe(Models.RedisChannels Key) ???????{ ???????????_sub.Unsubscribe(Key.ToString()); ???????} ???????#endregion ???????#region 数据转换 ???????/// <summary> ???????/// JSON转换配置文件 ???????/// </summary> ???????private static JsonSerializerSettings _jsoncfg = new JsonSerializerSettings ???????{ ???????????ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ???????????NullValueHandling = NullValueHandling.Ignore, ???????????Formatting = Formatting.None ???????}; ???????/// <summary> ???????/// 封装模型转换为字符串进行存储 ???????/// </summary> ???????/// <param name="value">值</param> ???????/// <returns></returns> ???????private static string ToJson(object value) ???????{ ???????????return ToJson<object>(value); ???????} ???????/// <summary> ???????/// 封装模型转换为字符串进行存储 ???????/// </summary> ???????/// <typeparam name="T">泛型</typeparam> ???????/// <param name="value">值</param> ???????/// <returns></returns> ???????private static string ToJson<T>(T value) ???????{ ???????????return JsonConvert.SerializeObject(new Models.RedisData<T> ???????????{ ???????????????Value = value ???????????}, _jsoncfg); ???????} ???????/// <summary> ???????/// 缓存字符串转为封装模型 ???????/// </summary> ???????/// <typeparam name="T"></typeparam> ???????/// <param name="value"></param> ???????/// <returns></returns> ???????private static Models.RedisData<T> JsonTo<T>(string value) ???????{ ???????????return JsonConvert.DeserializeObject<Models.RedisData<T>>(value, _jsoncfg); ???????} ???????private static T Recieve<T>(string cachevalue) ???????{ ???????????T result = default(T); ???????????bool flag = !string.IsNullOrWhiteSpace(cachevalue); ???????????if (flag) ???????????{ ???????????????var cacheObject = JsonConvert.DeserializeObject<Models.RedisData<T>>(cachevalue, _jsoncfg); ???????????????result = cacheObject.Value; ???????????} ???????????return result; ???????} ???????#endregion ???????#region 方法委托 ???????/// <summary> ???????/// 委托执行方法 ???????/// </summary> ???????/// <param name="d"></param> ???????public delegate void DoSub(object d); ???????#endregion ???}

二.在starup里注入

  

  AddRedisCacheService是我在RedisServiceExtensions里放的拓展方法,这里用来注入redis的配置,RedisOptionKey是我在预编译变量里放置的key,

  对应appsetting.json里配置文件的key

  如图:

  

  

  这里我们通过上一章的ConfigLocator很轻松的就拿到了redisOptions强类型的值

  到这里我们基本配置就完成,再说明一下,redisconfig的配置,redisName代表redis库名,redisHost代表链接库地址,redisPass代表密码

三.初级测试

  测试代码如下:

public IActionResult Index() ???????{ ???????????var key = "Test_Redis_Key"; ???????????var result= RedisServiceExtensions.Insert(key,"good"); ???????????var value = RedisServiceExtensions.Get(key); ???????????return View(); ???????}

  测试结果:

  

  result=true表示写入成功

  

  value=good恰好是我们刚才写的good

  初级对reids的测试就是这么简单,客户端连接数据库我就不演示了

四.redis高级测试

  高级测试我主要测试pub和sub并且要给大家演示出timeout那个问题,我争取将其复现了!

  首先强调一点pub和sub是有通道的,通道大家不陌生吧!

  如图:

  

  程序启动,我们先订阅一个通道,本此测试我订阅两个通道,根据有说服力!

  subscribe是一个泛型方法,泛型约束的是执行方法的参数类型,有两个入参,一个是通道名称,一个是要执行的委托方法

  代码如下:注意我这里将其做成拓展方法,并且开另一个线程执行

  

/// <summary> ???????/// 注册通道并执行对应方法 ???????/// </summary> ???????/// <typeparam name="T">数据类型</typeparam> ???????/// <param name="serviceCollection"></param> ???????/// <param name="Key">通道名</param> ???????/// <param name="doSub">方法</param> ???????public static IServiceCollection Subscribe<T>(this IServiceCollection serviceCollection,Models.RedisChannels Key, DoSub doSub) where T : class ???????{ ???????????Task.Run(() => ???????????{ ???????????????var _subscribe = connection.GetSubscriber(); ???????????????_subscribe.Subscribe(Key.ToString(), delegate (RedisChannel channel, RedisValue message) ???????????????{ ???????????????????T t = Recieve<T>(message); ???????????????????doSub(t); ???????????????}); ???????????}); ???????????return serviceCollection; ???????}

  RedisService.SubscribeDoSomething,RedisService.MemberChannel_SubscribeDoSomething是两个委托方法,我给第一个通道pub,他就执行一次SubscribeDoSomething

  给第二个通道pub,他就执行一次MemberChannel_SubscribeDoSomething

  这两个方法实现如下:

  

public class RedisService ???{ ???????public static void SubscribeDoSomething(object query) ???????{ ???????????int num = 0; ???????????Log4Net.Info($"TestPubSub_通道订阅_{num}"); ???????????num += 1; ???????} ???????public static void MemberChannel_SubscribeDoSomething(object query) ???????{ ???????????query= query as string; ???????????int num = 0; ???????????Log4Net.Info($"MemberChannel_SubscribeDoSomething_{query}_{num}"); ???????????num += 1; ???????} ???}

  接下来我还是在控制器里调用,进行pub  

public IActionResult Index() ???????{ ???????????//发布TestPubSub ???????????var result = RedisServiceExtensions.Publish( Infrastructrue.Caches.Redis.Models.RedisChannels.TestPubSub,null); ???????????//发布MemberRegister ???????????var result2 = RedisServiceExtensions.Publish(Infrastructrue.Caches.Redis.Models.RedisChannels.MemberRegister, "哥就是哥_不一样的烟火..."); ???????????return View(); ???????}

  测试结果:

  

  日志上成功记录下来,也就是说,pub出去的东西,sub到,然后执行写了日志!

  接下来我让控制器循环执行100次pub,我们让第二个通道的pub100次,第一个通道就pub一次

  代码如下:

public IActionResult Index() ???????{ ???????????//发布TestPubSub ???????????var result = RedisServiceExtensions.Publish(Infrastructrue.Caches.Redis.Models.RedisChannels.TestPubSub, null); ???????????for (int i = 0; i < 100; i++) ???????????{ ???????????????//发布MemberRegister ???????????????var result2 = RedisServiceExtensions.Publish(Infrastructrue.Caches.Redis.Models.RedisChannels.MemberRegister, "哥就是哥_不一样的烟火..."); ???????????} ???????????return View(); ???????}

  

  哈哈,太happy了,一次把我要说的那个问题------------timeout的问题测出来了!

  如图:

  

  详细信息如下:遇到的肯定是这个问题想都不用想

  

  Timeout performing PUBLISH MemberRegister (5000ms), inst: 24, qs: 0, in: 0, serverEndpoint: 39.107.202.142:6379, mgr: 9 of 10 available, clientName: GY, IOCP: (Busy=0,Free=1000,Min=4,Max=1000), WORKER: (Busy=5,Free=32762,Min=4,Max=32767), v: 2.0.513.63329 (Please take a look at this article for some common client-side issues that can cause timeouts: https://stackexchange.github.io/StackExchange.Redis/Timeouts)

  

  这个问题的根本原因在于我们配置的redis默认等待时间

  

  我现在用的是等待二十秒不行,如果改才600等待10分钟,你的timeout应该就不会出现了!(如有不对请斧正)

  这一篇就这样吧,下一篇我会唠唠这个系统的权限管理模块的实现

  • 下章管理系统模块实现

  

[外包]!采用asp.net core 快速构建小型创业公司后台管理系统(三)

原文地址:https://www.cnblogs.com/gdsblog/p/10004615.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved