.Net Core中的内存缓存实现——Redis及MemoryCache(2个可选)方案的实现

ASP.NET Core 支持多个不同的缓存。 最简单的缓存基于 IMemoryCache。 IMemoryCache 表示存储在 Web 服务器内存中的缓存。 在服务器场(多个服务器)中运行的应用应确保在使用内存中缓存时会话是粘滞的。 粘滞会话可确保来自客户端的请求都转到同一服务器。 例如,Azure Web 应用使用应用程序请求路由 (ARR) 将所有请求路由到同一服务器。Web 场中的非粘滞会话需要分布式缓存(如 Redis)来避免缓存一致性问题。

.NET 中有两个MemoryCache类:

  • System.Runtime.Caching.MemoryCache   
    已非推荐, .NET Standard 2.0 或更高版本。使用场景比如:将代码从 ASP.NET 4.x 移植到 ASP.NET Core 时,使用 System.Runtime.Caching/MemoryCache 作为兼容性桥。
  • Microsoft.Extensions.Caching.Memory.MemoryCache   
    推荐使用,因为它更好地集成到 ASP.NET Core 中。 MemoryCache实现IMemoryCache

引自官方说明:ASP.NET Core 中的内存中缓存 | Microsoft Learn

.NET Core中使用MemoryCache

调用自带的AddMemoryCache扩展方法,将IMemoryCache注入容器中,后面便可通过容器获取IMemoryCache的实现MemoryCache对本机内存缓存进行操纵

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMemoryCache();   //会注入IMemoryCache的实现类MemoryCache
using IHost host = builder.Build();

封装内存缓存工具类 

以下给出代码,通过对 ICacheTool接口 的两种实现,分别封装“本地MemoryCache”和“分布式Redis”两种方案的内存缓存实现,项目中根据需要选择一种作为 ICacheTool 的实现注入依赖容器即可。

1. MemoryCacheTool:

using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ZhonTai.Common.Extensions;namespace ZhonTai.Admin.Tools.Cache;/// <summary>
/// 内存缓存
/// </summary>
public partial class MemoryCacheTool : ICacheTool
{private static readonly string PatternRegex = @"\{.*\}";private readonly IMemoryCache _memoryCache;public MemoryCacheTool(IMemoryCache memoryCache){_memoryCache = memoryCache;}public List<string> Keys => GetAllKeys();public long Del(params string[] key){foreach (var k in key){_memoryCache.Remove(k);}return key.Length;}public Task<long> DelAsync(params string[] key){foreach (var k in key){_memoryCache.Remove(k);}return Task.FromResult(key.Length.ToLong());}public async Task<long> DelByPatternAsync(string pattern){if (pattern.IsNull())return default;pattern = Regex.Replace(pattern, PatternRegex, "(.*)");var keys = GetAllKeys().Where(k => Regex.IsMatch(k, pattern));if (keys != null && keys.Count() > 0){return await DelAsync(keys.ToArray());}return default;}public bool Exists(string key){return _memoryCache.TryGetValue(key, out _);}public Task<bool> ExistsAsync(string key){return Task.FromResult(_memoryCache.TryGetValue(key, out _));}public string Get(string key){return _memoryCache.Get(key)?.ToString();}public T Get<T>(string key){return _memoryCache.Get<T>(key);}public Task<string> GetAsync(string key){return Task.FromResult(Get(key));}public Task<T> GetAsync<T>(string key){return Task.FromResult(Get<T>(key));}public void Set(string key, object value){_memoryCache.Set(key, value);}public void Set(string key, object value, TimeSpan expire){_memoryCache.Set(key, value, expire);}public Task SetAsync(string key, object value, TimeSpan? expire = null){if(expire.HasValue){Set(key, value, expire.Value);}else{Set(key, value);}return Task.CompletedTask;}public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> func, TimeSpan? expire = null){if (await ExistsAsync(key)){try{return await GetAsync<T>(key);}catch{await DelAsync(key);}}var result = await func.Invoke();if (expire.HasValue){await SetAsync(key, result, expire.Value);}else{await SetAsync(key, result);}return result;}private List<string> GetAllKeys(){const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;var coherentState = _memoryCache.GetType().GetField("_coherentState", flags).GetValue(_memoryCache);var entries = coherentState.GetType().GetField("_entries", flags).GetValue(coherentState);var cacheItems = entries as IDictionary;var keys = new List<string>();if (cacheItems == null) return keys;foreach (DictionaryEntry cacheItem in cacheItems){keys.Add(cacheItem.Key.ToString());}return keys;}public List<string> GetKeysByPattern(string pattern){return GetAllKeys().Where(k => Regex.IsMatch(k, pattern)).ToList();}
}

2. RedisCacheTool: 

using FreeRedis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ZhonTai.Common.Extensions;namespace ZhonTai.Admin.Tools.Cache;/// <summary>
/// Redis缓存
/// </summary>
public partial class RedisCacheTool : ICacheTool
{private static readonly string PatternRegex = @"\{.*\}";private readonly RedisClient _redisClient;public List<string> Keys => _redisClient.Keys("*").ToList();public RedisCacheTool(RedisClient redisClient){_redisClient = redisClient;}public long Del(params string[] key){return _redisClient.Del(key);}public Task<long> DelAsync(params string[] key){return _redisClient.DelAsync(key);}public async Task<long> DelByPatternAsync(string pattern){if (pattern.IsNull())return default;pattern = Regex.Replace(pattern, PatternRegex, "*");var keys = await _redisClient.KeysAsync(pattern);if (keys != null && keys.Length > 0){return await _redisClient.DelAsync(keys);}return default;}public bool Exists(string key){return _redisClient.Exists(key);}public Task<bool> ExistsAsync(string key){return _redisClient.ExistsAsync(key);}public string Get(string key){return _redisClient.Get(key);}public T Get<T>(string key){return _redisClient.Get<T>(key);}public Task<string> GetAsync(string key){return _redisClient.GetAsync(key);}public Task<T> GetAsync<T>(string key){return _redisClient.GetAsync<T>(key);}public void Set(string key, object value){_redisClient.Set(key, value);}public void Set(string key, object value, TimeSpan expire){_redisClient.Set(key, value, expire);}public Task SetAsync(string key, object value, TimeSpan? expire = null){return _redisClient.SetAsync(key, value, expire.HasValue ? expire.Value.TotalSeconds.ToInt() : 0);}public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> func, TimeSpan? expire = null){if (await _redisClient.ExistsAsync(key)){try{return await _redisClient.GetAsync<T>(key);}catch{await _redisClient.DelAsync(key);}}var result = await func.Invoke();await _redisClient.SetAsync(key, result, expire.HasValue ? expire.Value.TotalSeconds.ToInt() : 0);return result;}public List<string> GetKeysByPattern(string pattern){return _redisClient.Keys(pattern).ToList();}
}

3. 根据配置选择其中一种内存缓存方案,作为ICacheTool接口的实现注入容器

...//缓存操作类相关注册
var cacheConfig = AppInfo.GetOptions<CacheConfig>(); //获取缓存相关配置//调用自带的AddMemoryCache扩展方法,将IMemoryCache注入容器(用于MemoryCache作为内存缓存的方案)
services.AddMemoryCache();if (cacheConfig.Type == CacheType.Redis)
{//【要使用Redis作为内存缓存的实现方案】//FreeRedis客户端var redis = new RedisClient(cacheConfig.Redis.ConnectionString){Serialize = JsonConvert.SerializeObject,Deserialize = JsonConvert.DeserializeObject};services.AddSingleton(redis);services.AddSingleton<IRedisClient>(redis);//Redis缓存services.AddSingleton<ICacheTool, RedisCacheTool>();//分布式Redis缓存services.AddSingleton<IDistributedCache>(new DistributedCache(redis));if(_hostAppOptions?.ConfigureIdGenerator != null){_hostAppOptions?.ConfigureIdGenerator?.Invoke(appConfig.IdGenerator);YitIdHelper.SetIdGenerator(appConfig.IdGenerator);}else{//分布式Id生成器services.AddIdGenerator();}
}
else
{//【要使用MemoryCache作为内存缓存的实现方案】//内存缓存services.AddSingleton<ICacheTool, MemoryCacheTool>();//分布式内存缓存services.AddDistributedMemoryCache();//Id生成器_hostAppOptions?.ConfigureIdGenerator?.Invoke(appConfig.IdGenerator);YitIdHelper.SetIdGenerator(appConfig.IdGenerator);
}

4. CacheConfig参考配置信息:

{"CacheConfig": {//缓存类型 Memory = 0,Redis = 1"type": "Memory",//限流缓存类型 Memory = 0,Redis = 1"typeRateLimit": "Memory",//Redis配置"redis": {//连接字符串"connectionString": "127.0.0.1:6379,password=,defaultDatabase=1",//限流连接字符串"connectionStringRateLimit": "127.0.0.1:6379,password=,defaultDatabase=1"}}
}

相关知识记录:

封装System.Runtime.Caching.MemoryCache实现服务端缓存,以及在依赖注入中使用时要注意的坑-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/381020.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5种梯度下降法的公式

5种梯度下降法的公式推演&#xff1a; 1. 梯度下降 (Gradient Descent) 梯度下降法的更新公式为&#xff1a; θ t 1 θ t − η ∇ θ J ( θ ) \theta_{t1} \theta_t - \eta \nabla_\theta J(\theta) θt1​θt​−η∇θ​J(θ) 其中&#xff0c; θ t \theta_t θt​…

Tomcat服务器

1.Tomcat定义以及作用 Web服务器是一个应用程序(软件)&#xff0c;对HTTP协议的操作进行封装&#xff0c;使得程序员不必直接对协议进行操作。(不用程序员自己写代码去解析http协议规则&#xff0c;比如不用考虑响应码的问题&#xff0c;以及响应数据应该如何写)&#xff0c;让…

ZK学习笔记

ZK 一.基本概念 Zookeeper是⼀个开源的分布式协调服务&#xff0c;其设计⽬标是将那些复杂的且容易出错的分布式⼀致性服务封装起来&#xff0c;构成⼀个⾼效可靠的原语集&#xff0c;并以⼀些简单的接⼝提供给⽤户使⽤。 zookeeper是⼀个典型的分布式数据⼀致性的解决⽅案&…

在 PostgreSQL 里如何实现数据的冷热数据分层存储的自动化策略调整?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 在 PostgreSQL 里如何实现数据的冷热数据分层存储的自动化策略调整 在 PostgreSQL 里如何实现数据的冷…

ip地址是电脑还是网线决定的

在数字化时代的浪潮中&#xff0c;网络已经成为了我们日常生活和工作不可或缺的一部分。当我们谈论网络时&#xff0c;IP地址无疑是一个核心的概念。然而&#xff0c;关于IP地址的分配和决定因素&#xff0c;很多人可能存在误解。有些人认为IP地址是由电脑决定的&#xff0c;而…

mybatisPlus和mybatis的版本冲突问题、若依换成MP、解决git无法推送、使用若依框架的swagger、以后再遇到团队项目应该怎么做。

20240716 一. mybatisPlus和mybatis的版本冲突问题1. 使用前的准备2. 我遇到了一个很严重的问题。3. 解决问题&#xff0c;好吧也没解决&#xff0c;发现问题&#xff01;&#xff01; 二、该死的git&#xff01;&#xff01;&#xff01;&#xff01;1. 解决无法在idea中使用g…

CBSD bhyve Ubuntu 配置vnc登录管理

CBSD介绍 CBSD是为FreeBSD jail子系统、bhyve、QEMU/NVMM和Xen编写的管理层。该项目定位为一个综合解决方案的单一集成工具&#xff0c;用于使用预定义的软件集以最少的配置快速构建和部署计算机虚拟环境。 虽然CBSD没有提供额外的操作系统级功能&#xff0c;但它极大地简化了…

fatal: not a git repository (or any of the parent directories): .git

问题描述&#xff1a; 通过git pull 拉取代码提示&#xff1a; fatal: not a git repository (or any of the parent directories): .git 这个错误信息表明你当前所在的目录不是一个 Git 仓库&#xff0c;或者任何父目录中都没有 .git 目录。 问题解决&#xff1a; 确认当前目…

Windows 、Linux、MacOS 进程管理机制

本心、输入输出、结果 文章目录 Windows 、Linux、MacOS 进程管理机制前言Windows 进程管理机制Linux 进程管理macOS 进程管理内存不够了,几个操作系统如何处理Windows 、Linux、MacOS 进程管理机制 编辑 | 简简单单 Online zuozuo 地址 | https://blog.csdn.net/qq_15071263 …

<数据集>混凝土缺陷检测数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;7353张 标注数量(xml文件个数)&#xff1a;7353 标注数量(txt文件个数)&#xff1a;7353 标注类别数&#xff1a;6 标注类别名称&#xff1a;[exposed reinforcement, rust stain, Crack, Spalling, Efflorescence…

JavaSE从零开始到精通

1.前置知识 JVM&#xff1a;java virtrual machine, java虚拟机, 专门用于执行java代码的一款软件。可以将class文件&#xff0c;转换为机器认识的机器码&#xff0c;因为我们的计算机只认识010101的二进制语言。JRE&#xff1a;java runtime enviroment, java运行时环境, jav…

CMake生成Debug和Release目标程序时的一些配置

文章介绍 本文章将介绍在Windows和Linux平台&#xff0c;生成可执行程序时&#xff0c;如何设置Debug和Release的一些属性。主要介绍如何设置目标程序的生成路径&#xff0c;以及运行时库的设置和目标程序版本号的设置。 Debug和Release模式 -O,-O1: 这两个命令的效果是一样…

C++学习笔记-C++11中的智能指针

1.智能指针介绍 智能指针是C的特性用法&#xff0c;是一个类似指针功能的类对象&#xff0c;其目的是为了更好的管理动态分配的内存&#xff0c;避免出现内存泄漏、悬空指针等问题。C11的标准库里提供了三种智能指针模板类&#xff0c;分别是std::unique_ptr、std::shared_ptr…

深入解析HNSW:Faiss中的层次化可导航小世界图

层次化可导航小世界&#xff08;HNSW&#xff09;图是向量相似性搜索中表现最佳的索引之一。HNSW 技术以其超级快速的搜索速度和出色的召回率&#xff0c;在近似最近邻&#xff08;ANN&#xff09;搜索中表现卓越。尽管 HNSW 是近似最近邻搜索中强大且受欢迎的算法&#xff0c;…

Flutter动画详解第二篇之显式动画(Explicit Animations)

目录 前言 一、定义 1.AnimationController 1.常用属性 1. value 2. status 3. duration 2.常用方法 1.forward 2.reverse 3.repeat 4.stop 5. reset 6. animateTo(double target, {Duration? duration, Curve curve Curves.linear}) 7.animateBack(double ta…

大数据之写入Doris数据问题

1. 解决Key columns should be a ordered prefix of the schema. KeyColumns[1] (starts from zero) is xxx, but 背景 create table if not exists XXX ( fathercorp varchar(50), id decimalv3(38,0) ) ENGINEOLAP UNIQUE KEY(id) COMMENT xxxx DISTRIBUTED BY HASH(id) BUC…

C#实现数据采集系统-实现功能介绍

系统介绍 我们这里主要使用C#( .Net 6)来实现一个数据采集系统&#xff0c;从0到1搭建数据采集系统&#xff0c;从系统分析&#xff0c;功能拆解&#xff0c;到一一实现 数据采集 数据采集是企业信息化和数字化转型过程中的关键环节&#xff0c;它涉及到从生产设备、传感器…

数据结构之细说链表

1.1顺序表的问题以及思考 经过上一篇顺序表的学习&#xff0c;我们知道顺序表还是有很多缺点 顺序表的缺点&#xff1a; 1.中间/头部的插入删除&#xff0c;实际复杂度为O(N) 2.增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗 3.扩容一般…

实战打靶集锦-31-monitoring

文章目录 1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 ssh服务4.2 smtp服务4.3 http/https服务 5. 系统提权5.1 枚举系统信息5.2 枚举passwd文件5.3 枚举定时任务5.4 linpeas提权 6. 获取flag 靶机地址&#xff1a;https://download.vulnhub.com/monitoring/Monitoring.o…

【BUG】已解决:python setup.py bdist_wheel did not run successfully.

已解决&#xff1a;python setup.py bdist_wheel did not run successfully. 目录 已解决&#xff1a;python setup.py bdist_wheel did not run successfully. 【常见模块错误】 解决办法&#xff1a; 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主…