当前位置:网站首页>在.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
边栏推荐
- TP5 multi conditional where query (using PHP variables)
- TP5 inherits base and uses the variables in base
- Using positive and negative traversal to solve the problem of "the shortest distance of characters"
- [ncnn] - the meaning of - 23300 in param
- Vs code setting line feed
- HLS / chisel uses CORDIC hyperbolic system to realize square root calculation
- LNMP MySQL allows remote access
- Distributed system services
- HLS / chisel practice CORDIC high performance computing complex square root
- Traversal of l2-006 tree (middle and later order determination binary tree & sequence traversal)
猜你喜欢
准备一个月去参加ACM,是一种什么体验?
基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客?
Ningde's position in the times is not guaranteed?
Array and collection types passed by openfeign parameters
Summary of software test interview questions
tf. keras. layers. MaxPooling? D function
Cloud computing learning 1 - openstack cloud computing installation and deployment steps with pictures and texts (Xiandian 2.2)
L2-006 樹的遍曆(中後序確定二叉樹&層序遍曆)
REINFORCE
Er and eer models
随机推荐
Numpy stack function
Using positive and negative traversal to solve the problem of "the shortest distance of characters"
MYSQL03_ SQL overview, rules and specifications, basic select statements, display table structure
Laravel new route file
Some problems encountered in setting Django pure interface, channel and MySQL on the pagoda panel
REINFORCE
How to use C language to realize [guessing numbers game]
中后二叉建树
Redis Cluster集群,主节点故障,主从切换后ip变化,客户端需要处理不
基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客?
In redis cluster, the master node fails, and the IP changes after the master-slave switch. The client does not need to deal with it
Use DFS to solve the problem of "number of dictionary rows"
微软是如何解决 PC 端程序多开问题的——内部实现
Simple example of using redis in PHP
Recursion - outputs continuously increasing numbers
Plug in for vscode
Load view Caton
Openfeign service call
Laravel's own paging query
Q-Learning & Sarsa