当前位置:网站首页>在.NE6 WebApi中使用分布式缓存Redis
在.NE6 WebApi中使用分布式缓存Redis
2022-04-23 03:06:00 【罗迪尼亚的熔岩】
首先安装Redis
https://github.com/MicrosoftArchive/redis/releases
https://github.com/cinience/RedisStudio/releases
Redis 启动和关闭
安装好之后,我们可以通过服务启动和关闭 Redis 了,我们可以查看系统的任务管理器,检查是否启动了 redis-server,下面是 redis-server 的启动和关闭命令:
$ redis-server.exe --service-start # 启动
$ redis-server.exe --service-stop # 关闭
使用 cli
确认 redis-server 启动之后,我们可以执行 redis 目录里面的 redis-cli.exe 文件,这样就可以连接上 Redis 了。当然,我们也可以通过命令行 CMD 来链接 Redis。
可以直接进行 Redis 存取了:
$ redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> set firstKey "moyufed"
OK
127.0.0.1:6379> get firstKey
"moyufed"
127.0.0.1:6379>
增加密码
在 Redis 的安装目录中,有 redis.windows.conf ,redis.windows-service.conf 两个文件,我们使用记事本打开(推荐Notepad++),找到需要设置密码的行,可以 Ctrl + F 查找 “requirepass” 的行(大概386行位置),分别设置 Redis 密码(去掉前面的 “#”),例子:
requirepass moyufed
使用 Redis
修改好之后重启 redis-server ,此时连接 Redis 之后进行 Redis 存取需要登录,例子:
Administrator@WIN-1706081829 C:\Users\Administrator
$ redis-server.exe --service-stop
[42636] 25 Feb 18:42:53.622 # Redis service successfully stopped.
Administrator@WIN-1706081829 C:\Users\Administrator
$ redis-server.exe --service-start
[38828] 25 Feb 18:42:58.576 # Redis service successfully started.
Administrator@WIN-1706081829 C:\Users\Administrator
$ redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> set firstKey "moyufed"
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth moyufed
OK
127.0.0.1:6379> set firstKey "moyufed"
OK
127.0.0.1:6379> get firstKey
"moyufed"
127.0.0.1:6379>
参考文档
Window配置Redis环境和简单使用:https://www.cnblogs.com/wxjnew/p/9160855.html
Windows下Redis安装配置和使用注意事项:https://www.cnblogs.com/LMJBlogs/p/11550170.html
首先配置.NET6的安装环境
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="6.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NModbus4.NetCore" Version="2.0.1" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" />
</ItemGroup>
</Project>
配置数据仓库:
public record Book
{
public int Id {
get; set; }
public string Name {
get; set; }
public double Price {
get; set; }
}
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
class BookConfig : IEntityTypeConfiguration<Book>
{
public void Configure(EntityTypeBuilder<Book> builder)
{
builder.ToTable("Books");
builder.HasKey(x => x.Id);
}
}
using Microsoft.EntityFrameworkCore;
public class MyDbContext : DbContext
{
private ConfigurationBuilder cfgBuilder = new ConfigurationBuilder();
private string path = Directory.GetCurrentDirectory();
public DbSet<Book> Books {
get; set; }
public MyDbContext()
{
//configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("Ipcfg.json").Build();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
cfgBuilder.AddJsonFile("VariableNode.json", optional: true, reloadOnChange: true);
IConfigurationRoot configRoot = cfgBuilder.Build();
string conn = configRoot.GetSection("ConnectionStrings:SqliteConnectionString").Value;
string connString = "Data Source=" + path + conn;
optionsBuilder.UseSqlite(connString);
}
}
{
"ConnectionStrings": {
"SqliteConnectionString": "\\bin\\Debug\\net6.0\\Database\\DbSqlite.db",
"MySQLConnectionString": "server=192.168.85.102; database=OneToMany; uid=root; pwd=123456;"
},
"ModbusNode": {
"Id": 1,
"NodeClassId": 1,
"Name": "ModbusTCPClient",
"Description": "1#ZG上位机测试",
"ModbusType": "2000",
"ConnectTimeOut": "2000",
"CreateTime": "0",
"ReConnectTime": "5000",
"IsActive": "True",
"MaxErrorTimes": "1",
"KeyWay": "VarName",
"UseAlarmCheck": "True",
"ServerURL": "127.0.0.1",
"Port": "502",
"DataFormat": "ABCD",
"VarNum": "6",
"Type": "ModbusTCP",
"SlaveID": "1",
"Length": "10",
"Start": "0",
"Variable": [
{
"Id": 1,
"Number": "1",
"Name": "Float1",
"Description": "40001-40002",
"Type": "ModbusTCP",
"VarAddress": 0,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40001-40002低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40001-40002低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40001-40002高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40001-40002高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "Float",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
},
{
"Id": 2,
"Number": "2",
"Name": "Float2",
"Description": "40003-40004",
"Type": "ModbusTCP",
"VarAddress": 2,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40003-40004低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40003-40004低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40003-40004高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40003-40004高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "Float",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
},
{
"Id": 3,
"Number": "3",
"Name": "Float3",
"Description": "40005-40006",
"Type": "ModbusTCP",
"VarAddress": 4,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40005-40006低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40005-40006低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40005-40006高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40005-40006高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "Float",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
},
{
"Id": 4,
"Number": "4",
"Name": "Float4",
"Description": "40007-40008",
"Type": "ModbusTCP",
"VarAddress": 6,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40003-40004低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40003-40004低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40003-40004高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40003-40004高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "Float",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
},
{
"Id": 5,
"Number": "5",
"Name": "Ushort1",
"Description": "40009",
"Type": "ModbusTCP",
"VarAddress": 8,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40009低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40009低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40009高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40009高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "UShort",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
},
{
"Id": 6,
"Number": "6",
"Name": "Ushort2",
"Description": "40010",
"Type": "ModbusTCP",
"VarAddress": 9,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40009低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40009低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40009高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40009高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "UShort",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
}
]
}
}
namespace RedisDemonWebApi
{
public interface IRepository
{
Book? GetBooksByIdAsync(int a);
}
}
namespace RedisDemonWebApi
{
public class Repository : IRepository
{
private MyDbContext db;
public Repository(MyDbContext db)
{
this.db = db;
}
public Book? GetBooksByIdAsync(int a)
{
Book? book = db.Books.Where(x => x.Id == a).SingleOrDefault();
if (book==null)
{
return null;
}
else
{
return book;
}
//return db.Books.Single(x => x.Id == a);
}
}
}
依赖注入 :
global using RedisDemonWebApi;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddMemoryCache();//内存缓存
builder.Services.AddScoped<IMemoryCacheHelper, MemoryCacheHelper>();
builder.Services.AddDbContext<MyDbContext>();
builder.Services.AddScoped<IRepository, Repository>();
builder.Services.AddStackExchangeRedisCache(opt =>
{
opt.Configuration = "localhost";
opt.InstanceName = "cache1_";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
控制器:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using System.Text.Json;
namespace RedisDemonWebApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{
private readonly IDistributedCache distCache;
private readonly IDistributedCacheHelper helper;
private readonly ILogger <TestController> logger;
private readonly IMemoryCache memCache;
private readonly IRepository repository;
public TestController(IRepository repository, IMemoryCache memCache, ILogger<TestController> logger, IDistributedCache distCache)
{
//this.distCache = distCache;
//this.helper = helper;
this.repository = repository;
this.memCache = memCache;
this.logger = logger;
this.distCache = distCache;
}
//[HttpGet]
//public string Now()
//{
// string s = distCache.GetString("Now");
// if (s == null)
// {
// s = DateTime.Now.ToString();
// var opt = new DistributedCacheEntryOptions();
// opt.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30);
// distCache.SetString("Now", s, opt);
// }
// return s;
//}
[HttpGet]
//public ActionResult<Book?> GetBookById(int Id)
//{
// Book? book = repository.GetBooksByIdAsync(Id);
// return Ok(book);
//}
//内存缓存
public async Task<ActionResult<Book?>> GetBookById(int Id)
{
logger.LogInformation($"开始执行GetBookById,Id={
Id}");
//先查找内存缓存, 没有再进入repository查找
Book? b = await memCache.GetOrCreateAsync("Book" + Id, async (e) =>
{
logger.LogInformation($"缓存中没找到,去数据库,Id={
Id}");
return repository.GetBooksByIdAsync(Id);
});
logger.LogInformation($"GetOrCreateAsync结果{
b}");
if (b == null)
{
return NotFound("找不到");
}
else
{
return Ok(b);
}
}
//分布式缓存
[HttpGet]
public async Task<ActionResult<Book?>> GetBookFromRedisById(int Id)
{
Book? book=null;
logger.LogInformation($"开始执行GetBookById,Id={
Id}");
//先去分布式缓存中寻找
string? s = await distCache.GetStringAsync("Book" + Id);
//如果没找到, 去数据库中去找, 然后存入分布式缓存
if (s==null)
{
logger.LogInformation($"缓存中没找到,去数据库找,Id={
Id}");
book = repository.GetBooksByIdAsync(Id);
//设置Redis中的过期时间opt
var opt = new DistributedCacheEntryOptions();
opt.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30);
//json序列化成字符串存入缓存中
await distCache.SetStringAsync("Book" + Id, JsonSerializer.Serialize(book), opt);
logger.LogInformation($"在数据库中找到,Id={
Id},将其序列化为字符串存入Redis");
}
//如果在缓存中找到, 需要将缓存中的字符串s反序列化为book
else
{
book = JsonSerializer.Deserialize<Book?>(s);
logger.LogInformation($"直接在Redis中找到了,Id={
Id}");
}
//都没找到就是不存在了
if (book==null)
{
logger.LogInformation($"数据库和Redis中都不存在Id={
Id}的书籍");
return NotFound("不存在");
}
else
{
return book;
}
}
}
}
使用Swagger 测试 :

日志 :
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7063
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5063
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: D:\cSharpe\code\RedisDemon1\RedisDemonWebApi\
info: RedisDemonWebApi.Controllers.TestController[0]
开始执行GetBookById,Id=2
info: RedisDemonWebApi.Controllers.TestController[0]
缓存中没找到,去数据库找,Id=2
info: RedisDemonWebApi.Controllers.TestController[0]
在数据库中找到,Id=2,将其序列化为字符串存入Redis
info: RedisDemonWebApi.Controllers.TestController[0]
开始执行GetBookById,Id=2
info: RedisDemonWebApi.Controllers.TestController[0]
直接在Redis中找到了,Id=2
Redis中 :

如果查询的Id对应的内容不存在, 则Redis也会把null值存在Redis, 这样避免了缓存穿透的问题

版权声明
本文为[罗迪尼亚的熔岩]所创,转载请带上原文链接,感谢
https://blog.csdn.net/helldoger/article/details/124348180
边栏推荐
- LNMP MySQL allows remote access
- How to deploy a website with only a server and no domain name?
- ASP.NET和ASP.NETCore多环境配置对比
- 利用正反遍历来解决“字符的最短距离”问题
- Niuke white moon race 5 [problem solving mathematics field]
- 准备一个月去参加ACM,是一种什么体验?
- [ncnn] - the meaning of - 23300 in param
- Some problems encountered in setting Django pure interface, channel and MySQL on the pagoda panel
- Simple example of using redis in PHP
- eventBus
猜你喜欢

Thoughts on the 2022 national network security competition of the national secondary vocational group (only one idea for myself) - network security competition questions (7)

全网讲的最细,软件测试度量,怎样优化软件测试成本提高效率---火爆

TP5 customization in extend directory succeeded and failed. Return information

C# 11 的这个新特性,我愿称之最强!

tf. keras. layers. Conv? D function

Summary of interface automation interview questions for software testing

Vs code setting line feed

Source code interpretation of Flink index parameters (read quantity, sent quantity, sent bytes, received bytes, etc.)

MYSQL03_ SQL overview, rules and specifications, basic select statements, display table structure

Opencv fills the rectangle with a transparent color
随机推荐
Due to 3 ²+ four ²= five ², Therefore, we call '3,4,5' as the number of Pythagorean shares, and find the array of all Pythagorean shares within n (including n).
Basic SQL (VIII) data update operation practice
C#中元组对象Tuple的使用
[ncnn] - the meaning of - 23300 in param
Plug in for vscode
使用split来解决“最常见的单词”问题
c#可变参数params的介绍
How to count the number of all files in a directory under win10 system
How to deploy a website with only a server and no domain name?
Use split to solve the "most common words" problem
全网讲的最细,软件测试度量,怎样优化软件测试成本提高效率---火爆
利用正反遍历来解决“字符的最短距离”问题
ASP.NET 6 中间件系列 - 执行顺序
Golden nine silver ten interview season, you are welcome to take away the interview questions (with detailed answer analysis)
c#语法糖模式匹配【switch 表达式】
Notes sur le développement de la tarte aux framboises (XII): commencer à étudier la suite UNO - 220 de la tarte aux framboises de contrôle industriel advantech (i): Introduction et fonctionnement du s
Basic workflow of CPU
Openfeign service call
如果通过 C# 实现对象的深复制 ?
交换二叉树中每个结点的左和右