当前位置: 首页 > news >正文

c#实现redis的调用与基础类

网上对于redis的操作有很多文档,但大多太复杂,对于初识者来说有门槛。鉴于我碰到的这种情况,特地写一个redis与c#的基础控制类,仅供参考;

我的环境是.net9+webapi    本文件适用于.netcore的任何程序,包括控制台

安装

首先需要安装依赖包:stackexchange.redis             

控制台执行:install package stackexchange.redis

安装完了如图:

演示示例

编写string类型的增加,查询,删除,以及覆盖的逻辑

/// <summary>
/// 写入字符串到 Redis
/// </summary>
/// <param name="key">Redis 键名</param>
/// <param name="value">要存入的字符串值</param>
/// <param name="expireMinutes">过期时间(分钟),0 表示不过期</param>
[HttpPost("string/set")]
public async Task<IActionResult> SetString([FromQuery] string key, [FromQuery] string value, [FromQuery] int expireMinutes)
{if (!await _redis.CheckRateLimitAsync($"rate:string:set:{userId}", 10, TimeSpan.FromMinutes(1)))return BadRequest("访问过于频繁,请稍后再试");TimeSpan? expiry = expireMinutes > 0 ? TimeSpan.FromMinutes(expireMinutes) : null;bool success = await _redis.SetStringAsync(key, value, expiry);return Ok(new { key, value, success });
}/// <summary>
/// 获取 Redis 中的字符串
/// </summary>
/// <param name="key">Redis 键名</param>
[HttpGet("string/get")]
public async Task<IActionResult> GetString([FromQuery] string key)
{var value = await _redis.GetStringRawAsync(key);return Ok(new { key, value = value.ToString() });
}/// <summary>
/// 删除 Redis 键
/// </summary>
/// <param name="key">Redis 键名</param>
[HttpDelete("string/delete")]
public async Task<IActionResult> DeleteKey([FromQuery] string key)
{bool deleted = await _redis.DeleteKeyAsync(key);return Ok(new { key, deleted });
}

赋值

启动服务;在api文档中调用:

请求之后,去数据库查看是否成功写入:

请求次数:限流使用,在调用CheckRateLimitAsync事件的时候设置了key为1,在达到指定测试会return报错提示,示例:  多次请求后数量累加:

查询

接口中查询看结果:

修改

如果需要更新值,设置一下When关键字,看文档可知:

always:默认值,只要有set事件就覆盖原值,也就达到了修改的目的

exists:只有值存在才修改

notexists:只有值不存在才添加

namespace StackExchange.Redis
{/// <summary>/// Indicates when this operation should be performed (only some variations are legal in a given context)./// </summary>public enum When{/// <summary>/// The operation should occur whether or not there is an existing value./// </summary>Always,/// <summary>/// The operation should only occur when there is an existing value./// </summary>Exists,/// <summary>/// The operation should only occur when there is not an existing value./// </summary>NotExists,}
}

具体设置代码:

_db.StringSetAsync(key, value, expiry, When.Always);

目前设置的是always

请求覆盖测试:

数据库查看:

修改成功。同时Exists和NotExists方法效果可自行测试。

删除

api请求测试:

数据库查看:

到此为止已演示整体功能和设置。

除string类型还添加了其他更多类型不再演示,调用方式类似,我把文件上传了,可下载调试,免费的,如被设置收费就是csdn搞的鬼

https://download.csdn.net/download/qq_53217825/92261067

不想下在的可以往下翻看实现

代码查看

program代码:

var builder = WebApplication.CreateBuilder(args);// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddOpenApi();// 注册 RedisService(构造函数读取 IConfiguration)
builder.Services.AddSingleton<RedisService>();// 注册后台服务(如果你需要延迟队列 / 队列消费者)
builder.Services.AddHostedService<DelayQueueBackgroundService>();
builder.Services.AddHostedService<MessageQueueBackgroundService>();builder.Services.AddLogging(config => config.AddConsole());var app = builder.Build();if (app.Environment.IsDevelopment())
{app.MapOpenApi();
}app.UseAuthorization();
app.MapControllers();
app.Run();

其中redis配置为:

这个为核心注册单例
// 注册 RedisService(构造函数读取 IConfiguration)
builder.Services.AddSingleton<RedisService>();这里为延迟队列,按需添加
// 注册后台服务(如果你需要延迟队列 / 队列消费者)
builder.Services.AddHostedService<DelayQueueBackgroundService>();
builder.Services.AddHostedService<MessageQueueBackgroundService>();

同时配置RedisService服务:

以下包括限流设置,string、hash、set、list、sortedSet  等常用设置

using Microsoft.Extensions.Configuration;
using StackExchange.Redis;
using System.Text.Json;
using System.Security.Cryptography;
using System.Text;public class RedisService : IDisposable
{private readonly IConnectionMultiplexer _conn;private readonly IDatabase _db;private readonly IConfiguration _config;// Lua 脚本:原子从 ZSET 中弹出最多 N 个 score <= now 的成员// KEYS[1] = zsetKey, ARGV[1] = now(ms), ARGV[2] = batchprivate const string PopDueLua = @"
local key = KEYS[1]
local maxScore = ARGV[1]
local count = tonumber(ARGV[2])
local items = redis.call('ZRANGEBYSCORE', key, '-inf', maxScore, 'LIMIT', 0, count)
if #items == 0 thenreturn {}
end
for i, v in ipairs(items) doredis.call('ZREM', key, v)
end
return items
";public RedisService(IConfiguration configuration){_config = configuration;var connStr = _config.GetValue<string>("Redis:ConnectionString") ?? "127.0.0.1:6379";var opts = ConfigurationOptions.Parse(connStr);opts.AbortOnConnectFail = false;_conn = ConnectionMultiplexer.Connect(opts);_db = _conn.GetDatabase(_config.GetValue<int>("Redis:Db")); // 默认 db = 0;如需其它 db,可调用 _conn.GetDatabase(index)}#region --- 设置redis ---/// <summary>/// 检查指定 key 是否超出限流次数/// </summary>/// <param name="key">限流标识 key(可根据用户、接口等自定义)</param>/// <param name="limit">最大访问次数</param>/// <param name="window">时间窗口</param>/// <returns>true 表示未超限,false 表示超限</returns>public async Task<bool> CheckRateLimitAsync(string key, int limit, TimeSpan window){var count = await _db.StringIncrementAsync(key);if (count == 1)await _db.KeyExpireAsync(key, window);return count <= limit;}#endregion#region --- 基础 String / Object ---/// <summary>/// 写入普通字符串到 Redis/// </summary>/// <param name="key">Redis 键名</param>/// <param name="value">要写入的字符串值</param>/// <param name="expiry">可选过期时间,null 表示不过期</param>/// <returns>返回 true 表示写入成功,false 表示失败</returns>// 注意:此操作没有分布式锁或限流,直接写入 Redispublic Task<bool> SetStringAsync(string key, string value, TimeSpan? expiry = null)=> _db.StringSetAsync(key, value, expiry);/// <summary>/// 写入普通字符串到 Redis/// </summary>/// <param name="key">Redis 键名</param>/// <param name="value">要写入的字符串值</param>/// <param name="expiry">可选过期时间,null 表示不过期</param>/// <returns>返回 true 表示写入成功,false 表示失败</returns>// 注意:此操作没有分布式锁或限流,直接写入 Redispublic Task<bool> SetStringNotExistsAsync(string key, string value, TimeSpan? expiry = null)=> _db.StringSetAsync(key, value, expiry, When.NotExists);/// <summary>/// 从 Redis 获取字符串值(原始值)/// </summary>/// <param name="key">Redis 键名</param>/// <returns>返回 RedisValue,如果键不存在返回 Null</returns>// 此操作无需锁,直接读取public Task<RedisValue> GetStringRawAsync(string key)=> _db.StringGetAsync(key);/// <summary>/// 删除指定键/// </summary>/// <param name="key">Redis 键名</param>/// <returns>返回 true 表示删除成功,false 表示键不存在</returns>// 可与分布式锁配合使用,避免并发删除造成冲突public Task<bool> DeleteKeyAsync(string key)=> _db.KeyDeleteAsync(key);/// <summary>/// 写入对象到 Redis(序列化为 JSON 字符串)/// </summary>/// <typeparam name="T">对象类型</typeparam>/// <param name="key">Redis 键名</param>/// <param name="obj">要写入的对象</param>/// <param name="expiry">可选过期时间</param>/// <returns>返回 true 表示写入成功</returns>// 无分布式锁/限流,需要并发安全请在调用前加锁public Task<bool> SetObjectAsync<T>(string key, T obj, TimeSpan? expiry = null)=> _db.StringSetAsync(key, JsonSerializer.Serialize(obj), expiry);/// <summary>/// 从 Redis 读取对象(JSON 反序列化为指定类型)/// </summary>/// <typeparam name="T">对象类型</typeparam>/// <param name="key">Redis 键名</param>/// <returns>返回对象,如果键不存在或值为空返回 default(T)</returns>// 此操作无需锁public async Task<T?> GetObjectAsync<T>(string key){var v = await _db.StringGetAsync(key);return v.IsNullOrEmpty ? default : JsonSerializer.Deserialize<T>(v!);}#endregion#region --- Hash 操作 ---/// <summary>/// 设置哈希表字段,可一次性设置多个字段/// </summary>/// <param name="key">Redis 哈希表的键名</param>/// <param name="fields">要设置的字段数组 HashEntry[]</param>/// <returns>返回任务对象,完成后表示操作已执行</returns>// 无分布式锁,建议在高并发场景下加锁或使用事务public Task HashSetAsync(string key, HashEntry[] fields)=> _db.HashSetAsync(key, fields);/// <summary>/// 获取哈希表所有字段及对应值/// </summary>/// <param name="key">Redis 哈希表的键名</param>/// <returns>返回 HashEntry[] 数组,如果键不存在返回空数组</returns>// 读取操作,无锁public Task<HashEntry[]> HashGetAllAsync(string key)=> _db.HashGetAllAsync(key);/// <summary>/// 获取哈希表指定字段的值/// </summary>/// <param name="key">Redis 哈希表的键名</param>/// <param name="field">要获取的字段名</param>/// <returns>返回字段值,如果字段不存在返回 Null</returns>// 读取操作,无锁public Task<RedisValue> HashGetAsync(string key, string field)=> _db.HashGetAsync(key, field);/// <summary>/// 删除哈希表中指定字段/// </summary>/// <param name="key">Redis 哈希表的键名</param>/// <param name="field">要删除的字段名</param>/// <returns>返回 true 表示字段删除成功,false 表示字段不存在</returns>// 删除操作,可配合分布式锁使用,保证并发安全public Task<bool> HashDeleteAsync(string key, string field)=> _db.HashDeleteAsync(key, field);#endregion#region --- Set 操作 ---/// <summary>/// 向 Set 添加成员/// </summary>/// <param name="key">Redis Set 的键名</param>/// <param name="member">要添加的成员</param>/// <returns>返回 true 表示添加成功,false 表示成员已存在</returns>// 可用于实现分布式去重,无需额外锁public Task<bool> SetAddAsync(string key, string member)=> _db.SetAddAsync(key, member);/// <summary>/// 判断成员是否存在于 Set 中/// </summary>/// <param name="key">Redis Set 的键名</param>/// <param name="member">要判断的成员</param>/// <returns>返回 true 表示存在,false 表示不存在</returns>// 读取操作,无锁public Task<bool> SetContainsAsync(string key, string member)=> _db.SetContainsAsync(key, member);/// <summary>/// 从 Set 中移除指定成员/// </summary>/// <param name="key">Redis Set 的键名</param>/// <param name="member">要移除的成员</param>/// <returns>返回 true 表示移除成功,false 表示成员不存在</returns>// 移除操作,可配合分布式锁使用public Task<bool> SetRemoveAsync(string key, string member)=> _db.SetRemoveAsync(key, member);#endregion#region --- 普通消息队列(List) ---/// <summary>/// 推入队列(右侧入队)/// </summary>// 队列入队操作,可配合限流使用,确保高并发下不会刷爆队列public Task<long> EnqueueAsync(string queueKey, string message)=> _db.ListRightPushAsync(queueKey, message);/// <summary>/// 非阻塞取出(左侧出队),队列空时返回 Null/// </summary>// 出队操作,可配合分布式锁保证单消费者处理任务安全public Task<RedisValue> DequeueAsync(string queueKey)=> _db.ListLeftPopAsync(queueKey);/// <summary>/// 阻塞取出(BRPOP/BLPOP 风格)/// </summary>// 阻塞队列操作,可配合限流或分布式锁public async Task<RedisValue?> BlockingDequeueAsync(string queueKey, int timeoutSeconds = 0){var res = await _db.ExecuteAsync("BLPOP", queueKey, timeoutSeconds);if (res.IsNull) return null;var arr = (RedisResult[])res;if (arr.Length >= 2){return (RedisValue)arr[1];}return null;}#endregion#region --- 延迟队列(SortedSet) ---/// <summary>/// 添加一个延迟任务/// </summary>// 延迟任务添加,推荐加分布式锁,避免重复入队public Task<bool> AddDelayTaskAsync(string zsetKey, string value, TimeSpan delay){double score = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + delay.TotalMilliseconds;return _db.SortedSetAddAsync(zsetKey, value, score);}/// <summary>/// 原子弹出到期任务/// </summary>// 使用 Lua 脚本保证原子性,推荐配合分布式锁或限流public async Task<RedisValue[]> PopDueDelayTasksAsync(string zsetKey, int batch = 10){var nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();var result = (RedisResult[])await _db.ScriptEvaluateAsync(PopDueLua, new RedisKey[] { zsetKey }, new RedisValue[] { nowMs, batch });return result.Select(r => (RedisValue)r).ToArray();}#endregion#region --- 分布式锁 ---/// <summary>/// 尝试获取锁/// </summary>// 这是分布式锁核心方法public Task<bool> AcquireLockAsync(string resourceKey, string token, TimeSpan expiry)=> _db.LockTakeAsync(resourceKey, token, expiry);/// <summary>/// 释放锁(安全释放)/// </summary>// 分布式锁安全释放public async Task<bool> ReleaseLockSafeAsync(string resourceKey, string token){const string lua = @"
if redis.call('get', KEYS[1]) == ARGV[1] thenreturn redis.call('del', KEYS[1])
elsereturn 0
end
";var res = await _db.ScriptEvaluateAsync(lua, new RedisKey[] { resourceKey }, new RedisValue[] { token });return (int)res == 1;}/// <summary>/// 生成随机 token,可用于分布式锁/// </summary>public static string CreateLockToken() => Guid.NewGuid().ToString("N");#endregion#region --- 发布/订阅 ---/// <summary>/// 发布消息/// </summary>// 发布操作,可配合限流public Task<long> PublishAsync(string channel, string message)=> _conn.GetSubscriber().PublishAsync(channel, message);/// <summary>/// 订阅频道/// </summary>// 订阅操作无需锁,但处理回调时可能需要限流public void Subscribe(string channel, Action<RedisChannel, RedisValue> handler)=> _conn.GetSubscriber().Subscribe(channel, handler);/// <summary>/// 取消订阅/// </summary>// 取消订阅操作public void Unsubscribe(string channel, Action<RedisChannel, RedisValue> handler)=> _conn.GetSubscriber().Unsubscribe(channel, handler);#endregion#region --- 辅助方法 ---/// <summary>生成任务唯一 id(如果需要把任务 body 做为 id 的话)</summary>public static string Sha1Hex(string text){using var sha = SHA1.Create();var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(text));return Convert.ToHexString(bytes);}#endregionpublic void Dispose(){try { _conn?.Dispose(); } catch { }}
}

在使用端:

添加了一个api调用控制器。包括全部的调用以及注释

using Microsoft.AspNetCore.Mvc;
using StackExchange.Redis;
using System.Text.Json;[ApiController]
[Route("api/redis")]
public class RedisController : ControllerBase
{private readonly RedisService _redis;public RedisController(RedisService redis){_redis = redis;}int userId = 001;#region --- String / Object 操作 ---/// <summary>/// 写入字符串到 Redis/// </summary>/// <param name="key">Redis 键名</param>/// <param name="value">要存入的字符串值</param>/// <param name="expireMinutes">过期时间(分钟),0 表示不过期</param>[HttpPost("string/set")]public async Task<IActionResult> SetString([FromQuery] string key, [FromQuery] string value, [FromQuery] int expireMinutes){if (!await _redis.CheckRateLimitAsync($"rate:string:set:{userId}", 10, TimeSpan.FromMinutes(1)))return BadRequest("访问过于频繁,请稍后再试");TimeSpan? expiry = expireMinutes > 0 ? TimeSpan.FromMinutes(expireMinutes) : null;bool success = await _redis.SetStringAsync(key, value, expiry);return Ok(new { key, value, success });}/// <summary>/// 获取 Redis 中的字符串/// </summary>/// <param name="key">Redis 键名</param>[HttpGet("string/get")]public async Task<IActionResult> GetString([FromQuery] string key){var value = await _redis.GetStringRawAsync(key);return Ok(new { key, value = value.ToString() });}/// <summary>/// 删除 Redis 键/// </summary>/// <param name="key">Redis 键名</param>[HttpDelete("string/delete")]public async Task<IActionResult> DeleteKey([FromQuery] string key){bool deleted = await _redis.DeleteKeyAsync(key);return Ok(new { key, deleted });}/// <summary>/// 写入对象到 Redis(JSON 序列化)/// </summary>/// <param name="key">Redis 键名</param>/// <param name="obj">要存入的对象</param>/// <param name="expireMinutes">过期时间(分钟),0 表示不过期</param>[HttpPost("object/set")]public async Task<IActionResult> SetObject([FromQuery] string key, [FromBody] object obj, [FromQuery] int expireMinutes){TimeSpan? expiry = expireMinutes > 0 ? TimeSpan.FromMinutes(expireMinutes) : null;bool success = await _redis.SetObjectAsync(key, obj, expiry);return Ok(new { key, obj, success });}/// <summary>/// 获取 Redis 中的对象(JSON 反序列化)/// </summary>/// <param name="key">Redis 键名</param>[HttpGet("object/get")]public async Task<IActionResult> GetObject([FromQuery] string key){var obj = await _redis.GetObjectAsync<dynamic>(key);return Ok(new { key, obj });}#endregion#region --- Hash 操作 ---/// <summary>/// 设置哈希表字段/// </summary>/// <param name="key">Redis 哈希表键名</param>/// <param name="fields">要设置的字段和值</param>[HttpPost("hash/set")]public async Task<IActionResult> HashSet([FromQuery] string key, [FromBody] HashEntry[] fields){await _redis.HashSetAsync(key, fields);return Ok(new { key, fields });}/// <summary>/// 获取哈希表所有字段和值/// </summary>/// <param name="key">Redis 哈希表键名</param>[HttpGet("hash/getall")]public async Task<IActionResult> HashGetAll([FromQuery] string key){var fields = await _redis.HashGetAllAsync(key);return Ok(fields.Select(f => new { f.Name, f.Value }));}/// <summary>/// 获取哈希表指定字段/// </summary>/// <param name="key">Redis 哈希表键名</param>/// <param name="field">字段名</param>[HttpGet("hash/get")]public async Task<IActionResult> HashGet([FromQuery] string key, [FromQuery] string field){var value = await _redis.HashGetAsync(key, field);return Ok(new { key, field, value = value.ToString() });}/// <summary>/// 删除哈希表字段/// </summary>/// <param name="key">Redis 哈希表键名</param>/// <param name="field">字段名</param>[HttpDelete("hash/delete")]public async Task<IActionResult> HashDelete([FromQuery] string key, [FromQuery] string field){bool deleted = await _redis.HashDeleteAsync(key, field);return Ok(new { key, field, deleted });}#endregion#region --- Set 操作 ---/// <summary>/// 向 Set 添加成员/// </summary>/// <param name="key">Redis Set 键名</param>/// <param name="member">成员值</param>[HttpPost("set/add")]public async Task<IActionResult> SetAdd([FromQuery] string key, [FromQuery] string member){bool added = await _redis.SetAddAsync(key, member);return Ok(new { key, member, added });}/// <summary>/// 判断成员是否存在于 Set/// </summary>/// <param name="key">Redis Set 键名</param>/// <param name="member">成员值</param>[HttpGet("set/contains")]public async Task<IActionResult> SetContains([FromQuery] string key, [FromQuery] string member){bool exists = await _redis.SetContainsAsync(key, member);return Ok(new { key, member, exists });}/// <summary>/// 从 Set 移除成员/// </summary>/// <param name="key">Redis Set 键名</param>/// <param name="member">成员值</param>[HttpDelete("set/remove")]public async Task<IActionResult> SetRemove([FromQuery] string key, [FromQuery] string member){bool removed = await _redis.SetRemoveAsync(key, member);return Ok(new { key, member, removed });}#endregion#region --- 队列操作(List) ---/// <summary>/// 入队(右入队)/// </summary>/// <param name="queueKey">队列键名</param>/// <param name="message">要入队的消息</param>[HttpPost("queue/enqueue")]public async Task<IActionResult> QueueEnqueue([FromQuery] string queueKey, [FromQuery] string message){long length = await _redis.EnqueueAsync(queueKey, message);return Ok(new { queueKey, message, length });}/// <summary>/// 出队(左出队,非阻塞)/// </summary>/// <param name="queueKey">队列键名</param>[HttpGet("queue/dequeue")]public async Task<IActionResult> QueueDequeue([FromQuery] string queueKey){var message = await _redis.DequeueAsync(queueKey);return Ok(new { queueKey, message = message.ToString() });}/// <summary>/// 阻塞出队(可设置超时)/// </summary>/// <param name="queueKey">队列键名</param>/// <param name="timeoutSeconds">超时时间,0 表示永久阻塞</param>[HttpGet("queue/blockingdequeue")]public async Task<IActionResult> QueueBlockingDequeue([FromQuery] string queueKey, [FromQuery] int timeoutSeconds){var message = await _redis.BlockingDequeueAsync(queueKey, timeoutSeconds);return Ok(new { queueKey, message = message?.ToString() });}#endregion#region --- 延迟队列(SortedSet) ---/// <summary>/// 添加延迟任务/// </summary>/// <param name="zsetKey">SortedSet 键名</param>/// <param name="payload">任务内容(JSON)</param>/// <param name="delaySeconds">延迟时间(秒)</param>[HttpPost("delay/add")]public async Task<IActionResult> DelayAdd([FromQuery] string zsetKey, [FromBody] string payload, [FromQuery] int delaySeconds){bool added = await _redis.AddDelayTaskAsync(zsetKey, payload, TimeSpan.FromSeconds(delaySeconds));return Ok(new { zsetKey, payload, added });}/// <summary>/// 弹出到期任务/// </summary>/// <param name="zsetKey">SortedSet 键名</param>/// <param name="batch">最多弹出条数</param>[HttpGet("delay/pop")]public async Task<IActionResult> DelayPop([FromQuery] string zsetKey, [FromQuery] int batch){var items = await _redis.PopDueDelayTasksAsync(zsetKey, batch);return Ok(new { zsetKey, items });}#endregion#region --- 分布式锁 ---/// <summary>/// 获取分布式锁/// </summary>/// <param name="key">锁键名</param>/// <param name="expirySeconds">锁过期时间(秒)</param>[HttpPost("lock/acquire")]public async Task<IActionResult> LockAcquire([FromQuery] string key, [FromQuery] int expirySeconds){string token = RedisService.CreateLockToken();bool acquired = await _redis.AcquireLockAsync(key, token, TimeSpan.FromSeconds(expirySeconds));return Ok(new { key, token, acquired });}/// <summary>/// 释放分布式锁/// </summary>/// <param name="key">锁键名</param>/// <param name="token">锁 token(获取锁时返回)</param>[HttpPost("lock/release")]public async Task<IActionResult> LockRelease([FromQuery] string key, [FromQuery] string token){bool released = await _redis.ReleaseLockSafeAsync(key, token);return Ok(new { key, token, released });}#endregion#region --- 发布 / 订阅 ---/// <summary>/// 发布消息/// </summary>/// <param name="channel">频道名</param>/// <param name="message">消息内容</param>[HttpPost("pub/publish")]public async Task<IActionResult> Publish([FromQuery] string channel, [FromQuery] string message){long subscribers = await _redis.PublishAsync(channel, message);return Ok(new { channel, message, subscribers });}/// <summary>/// 订阅频道/// </summary>/// <param name="channel">频道名</param>[HttpPost("pub/subscribe")]public IActionResult Subscribe([FromQuery] string channel){_redis.Subscribe(channel, (ch, msg) =>{Console.WriteLine($"Channel: {ch}, Message: {msg}");});return Ok(new { channel, subscribed = true });}/// <summary>/// 取消订阅频道/// </summary>/// <param name="channel">频道名</param>[HttpPost("pub/unsubscribe")]public IActionResult Unsubscribe([FromQuery] string channel){_redis.Unsubscribe(channel, (ch, msg) =>{Console.WriteLine($"Unsubscribed Channel: {ch}");});return Ok(new { channel, unsubscribed = true });}#endregion
}

appsetting配置端:

其中connectionString为连接地址;

Db为数据库,需特别注意,其他项可看情况添加

{"Redis": {"ConnectionString": "127.0.0.1:6379","Db": 1,"DelayQueueKey": "delayed_tasks","DeadLetterQueueKey": "dlq","RetryPrefix": "retry_count:","LuaPopBatchSize": 10,"ConsumerPollIntervalMs": 500,"MaxRetryTimes": 5},"Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning"}}
}

http://www.dtcms.com/a/581756.html

相关文章:

  • 【深度学习新浪潮】什么是投机解码?大模型推理优化的核心技术解析(含代码实操)
  • Verilog函数function
  • 做电商宠物带哪个网站最好网络营销方法的选择
  • 超融合系统七大核心技术详解
  • Spring Boot 2.7.18(最终 2.x 系列版本)1 - 技术选型:连接池技术选型对比;接口文档技术选型对比
  • 从0到1做一个“字母拼词”Unity小游戏(含源码/GIF)- 单词字母打乱及字母拼词填空逻辑
  • 记一次 Maven 3.8.3 无法下载 HTTP 仓库依赖的排查历程
  • Linux网络初始及网络通信基本原理
  • 免费学软件的自学网站微信app制作
  • Foundation 模态框
  • 赣州深科网站建设深圳商城网站设计电话
  • vllm学习笔记之 PD分离 kv connector
  • 有经验的佛山网站设计东莞华为外包公司
  • 什么是AIGC的创作者?
  • 51单片机基础-GPIO结构详解
  • 织梦系统如何做网站专属头像制作免费
  • 2025高校网络安全管理运维赛--电子取证分析师赛道-决赛WriteUp
  • 蒲公英异地组网路由器全新固件:4G联网、策略路由、日志管理升级
  • 网站建设规划总结做高考题的网站
  • wordpress网站被镜像wordpress邮件功能用不了
  • (111页PPT)智能工厂总体设计方案(附下载方式)
  • sh -c
  • 在若依框架中修改了 Vue 路由的 base 路径后,还需要修改以下几个地方才能正常访问?
  • Spring Boot 注册登录接口进阶(bcrypt密码加密 + Apifox 测试)
  • 重庆住房城乡建设厅官方网站自己做直播网站
  • 服装网站制作网站建设需要的条件
  • 【把Linux“聊”明白】编译器gcc/g++与调试器gdb/cgdb:从编译原理到高效调试
  • LeetCode算法日记 - Day 96: 最长回文子串
  • 汽车ECU诊断刷写和OTA升级中的验签和校验
  • 网站主题旁边的图标怎么做的套模板网站