Smart.StackRedis
5.0.0
dotnet add package Smart.StackRedis --version 5.0.0
NuGet\Install-Package Smart.StackRedis -Version 5.0.0
<PackageReference Include="Smart.StackRedis" Version="5.0.0" />
<PackageVersion Include="Smart.StackRedis" Version="5.0.0" />
<PackageReference Include="Smart.StackRedis" />
paket add Smart.StackRedis --version 5.0.0
#r "nuget: Smart.StackRedis, 5.0.0"
#:package Smart.StackRedis@5.0.0
#addin nuget:?package=Smart.StackRedis&version=5.0.0
#tool nuget:?package=Smart.StackRedis&version=5.0.0
Smart.StackRedis
<a name="english"></a>
English
Smart.StackRedis is a Redis helper library built on StackExchange.Redis. It provides dependency injection support, key prefixing, JSON serialization, Redis data type modules, distributed lock helpers, counters, transactions, and pub/sub (StackExchange.Redis restores subscriptions automatically after a reconnect). It supports .NET 8, 9, and 10.
Installation
dotnet add package Smart.StackRedis
Registration
using Microsoft.Extensions.DependencyInjection;
using Smart.StackRedis;
services.AddSmartRedis(new RedisOptions
{
Server = "127.0.0.1:6379,password=password,abortConnect=false",
Prefix = "prod:",
ConnectTimeout = 15000,
SyncTimeout = 5000,
AbortOnConnectFail = false,
ConnectRetry = 3
});
Examples
public class UserService
{
private readonly SmartRedisService _redis;
public UserService(SmartRedisService redis)
{
_redis = redis;
}
public Task<bool> CacheUserAsync(User user)
{
return _redis.String.SetAsync($"users:{user.Id}", user, TimeSpan.FromHours(1));
}
public Task<User?> GetUserAsync(string userId)
{
return _redis.String.GetAsync<User>($"users:{userId}");
}
}
await redis.Hash.SetAsync("profiles:1", "name", "Tom");
string? name = await redis.Hash.GetAsync("profiles:1", "name");
await redis.List.RightPushAsync("jobs", job);
Job? next = await redis.List.LeftPopAsync<Job>("jobs");
await redis.Set.AddAsync("tags", new List<string> { "redis", "cache" });
string[] tags = await redis.Set.GetAllMembersAsync("tags");
string lockToken = Guid.NewGuid().ToString("N"); // value must be unique to the lock holder
bool locked = await redis.Lock.TakeAsync("order:1", lockToken, expiry: 30);
try
{
if (locked)
{
await ProcessOrderAsync();
}
}
finally
{
if (locked)
{
await redis.Lock.ReleaseAsync("order:1", lockToken);
}
}
await redis.Counter.InitialValueAsync("article:1:views", 0);
long views = await redis.Counter.IncrementAsync("article:1:views");
long current = await redis.Counter.CurrentValueAsync("article:1:views");
redis.SubscribeReceived += (channel, message) =>
{
Console.WriteLine($"Received message on {channel}: {message}");
};
await redis.Subscribe.SubscribeAsync("notifications");
await redis.Subscribe.PublishAsync("notifications", "hello");
Configuration Notes
RedisOptions wins over the connection string for the settings it exposes; set a property to null to fall back to the connection-string value.
services.AddSmartRedis(new RedisOptions
{
Server = "127.0.0.1:6379,password=password",
Prefix = "prod:",
ConnectTimeout = null, // keep the value from the connection string
AllowAdmin = false // FLUSHALL / CONFIG / SHUTDOWN stay disabled
});
| Topic | Behaviour |
|---|---|
| Key prefix | Applied to every key handled by the modules. GetDatabase(), GetTransaction() and pub/sub channels are not prefixed |
| Empty strings | Returned as-is. GetAsync returns null only when the key does not exist |
| Reconnection | StackExchange.Redis reconnects and restores subscriptions automatically; the library does not re-subscribe manually |
| Admin commands | Disabled by default (AllowAdmin = false) |
| Pub/sub | SubscribeReceived is a single event for all channels — dispatch by the channel argument |
| Distributed lock | value must be globally unique (a Guid is recommended); there is no auto-renewal |
| Stream | CreateConsumerGroupAsync is idempotent and creates the stream when missing; pass maxLength to AddAsync to bound growth |
Stream Example
// Create the group once (idempotent, creates the stream if it does not exist yet)
await redis.Stream.CreateConsumerGroupAsync("orders", "billing", "$");
// Bound the stream so it cannot grow forever
string? messageId = await redis.Stream.AddAsync("orders", "payload", json, maxLength: 100_000);
StreamEntry[] entries = await redis.Stream.ReadGroupAsync("orders", "billing", "worker-1", "$", count: 10);
foreach (StreamEntry entry in entries)
{
await redis.Stream.AcknowledgeAsync("orders", "billing", entry.Id);
}
Modules
| Module | Description |
|---|---|
Key |
Redis key operations (Exists / Delete) |
String |
String and JSON object storage |
Hash |
Hash field operations |
List |
List operations |
Set |
Set operations |
SortedSet |
Sorted set operations |
Stream |
Redis stream operations |
Lock |
Distributed lock helpers |
Counter |
Atomic counter helpers |
Subscribe |
Publish/subscribe helpers |
<a name="chinese"></a>
中文
Smart.StackRedis 是基于 StackExchange.Redis 的 Redis 工具库,提供依赖注入、键前缀、JSON 序列化、Redis 数据类型模块、分布式锁、计数器、事务和发布订阅能力(断线后的重新订阅由 StackExchange.Redis 自动完成)。兼容 .NET 8/9/10。
安装
dotnet add package Smart.StackRedis
注册
using Microsoft.Extensions.DependencyInjection;
using Smart.StackRedis;
services.AddSmartRedis(new RedisOptions
{
Server = "127.0.0.1:6379,password=password,abortConnect=false",
Prefix = "prod:",
ConnectTimeout = 15000,
SyncTimeout = 5000,
AbortOnConnectFail = false,
ConnectRetry = 3
});
示例
public class UserService
{
private readonly SmartRedisService _redis;
public UserService(SmartRedisService redis)
{
_redis = redis;
}
public Task<bool> CacheUserAsync(User user)
{
return _redis.String.SetAsync($"users:{user.Id}", user, TimeSpan.FromHours(1));
}
public Task<User?> GetUserAsync(string userId)
{
return _redis.String.GetAsync<User>($"users:{userId}");
}
}
await redis.Hash.SetAsync("profiles:1", "name", "Tom");
string? name = await redis.Hash.GetAsync("profiles:1", "name");
await redis.List.RightPushAsync("jobs", job);
Job? next = await redis.List.LeftPopAsync<Job>("jobs");
await redis.Set.AddAsync("tags", new List<string> { "redis", "cache" });
string[] tags = await redis.Set.GetAllMembersAsync("tags");
string lockToken = Guid.NewGuid().ToString("N"); // value must be unique to the lock holder
bool locked = await redis.Lock.TakeAsync("order:1", lockToken, expiry: 30);
try
{
if (locked)
{
await ProcessOrderAsync();
}
}
finally
{
if (locked)
{
await redis.Lock.ReleaseAsync("order:1", lockToken);
}
}
await redis.Counter.InitialValueAsync("article:1:views", 0);
long views = await redis.Counter.IncrementAsync("article:1:views");
long current = await redis.Counter.CurrentValueAsync("article:1:views");
redis.SubscribeReceived += (channel, message) =>
{
Console.WriteLine($"在 {channel} 收到消息: {message}");
};
await redis.Subscribe.SubscribeAsync("notifications");
await redis.Subscribe.PublishAsync("notifications", "hello");
配置与行为说明
RedisOptions 中显式赋值的属性会覆盖连接字符串中的同名参数;将属性设为 null 则以连接字符串为准。
services.AddSmartRedis(new RedisOptions
{
Server = "127.0.0.1:6379,password=password",
Prefix = "prod:",
ConnectTimeout = null, // 沿用连接字符串中的设置
AllowAdmin = false // 默认关闭 FLUSHALL / CONFIG / SHUTDOWN
});
| 主题 | 行为 |
|---|---|
| 键前缀 | 所有模块方法都会自动附加前缀;GetDatabase()、GetTransaction() 与发布订阅频道不会附加 |
| 空字符串 | 原样返回;GetAsync 仅在键不存在时返回 null |
| 断线重连 | 由 StackExchange.Redis 自动重连并恢复订阅,库内不再手工重新订阅 |
| 管理命令 | 默认关闭(AllowAdmin = false) |
| 发布订阅 | SubscribeReceived 是所有频道共用的单一事件,需按 channel 参数自行分发 |
| 分布式锁 | value 必须全局唯一(建议使用 Guid),且不提供自动续期 |
| Stream | CreateConsumerGroupAsync 幂等,流不存在时自动创建;AddAsync 传入 maxLength 可限制长度 |
Stream 示例
// 创建消费者组(幂等;流不存在时自动创建)
await redis.Stream.CreateConsumerGroupAsync("orders", "billing", "$");
// 限制流长度,避免无界增长
string? messageId = await redis.Stream.AddAsync("orders", "payload", json, maxLength: 100_000);
StreamEntry[] entries = await redis.Stream.ReadGroupAsync("orders", "billing", "worker-1", "$", count: 10);
foreach (StreamEntry entry in entries)
{
await redis.Stream.AcknowledgeAsync("orders", "billing", entry.Id);
}
模块
| 模块 | 说明 |
|---|---|
Key |
Redis Key 操作(Exists / Delete) |
String |
字符串和 JSON 对象存储 |
Hash |
Hash 字段操作 |
List |
List 操作 |
Set |
Set 操作 |
SortedSet |
Sorted Set 操作 |
Stream |
Redis Stream 操作 |
Lock |
分布式锁 |
Counter |
原子计数器 |
Subscribe |
发布订阅 |
Developed by zenglei
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.8)
- StackExchange.Redis (>= 2.13.1)
-
net8.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.8)
- StackExchange.Redis (>= 2.13.1)
-
net9.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.8)
- StackExchange.Redis (>= 2.13.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.0.0 | 81 | 10/19/2026 |
| 4.2.2 | 155 | 5/16/2026 |
| 4.2.1 | 141 | 3/19/2026 |
| 4.2.0 | 142 | 2/14/2026 |
| 4.1.1 | 143 | 2/11/2026 |
| 4.1.0 | 148 | 2/9/2026 |
| 4.0.1 | 159 | 12/30/2025 |
| 4.0.0 | 238 | 4/5/2025 |
| 3.2.0 | 236 | 3/27/2025 |
| 3.1.1 | 238 | 3/16/2025 |
| 3.1.0 | 188 | 2/26/2025 |
| 3.0.1 | 210 | 2/15/2025 |
| 3.0.0 | 214 | 2/15/2025 |
| 2.1.2 | 214 | 2/13/2025 |
| 2.1.1 | 226 | 2/9/2025 |
| 2.1.0 | 206 | 12/29/2024 |
| 2.0.2 | 240 | 12/7/2024 |
| 2.0.1 | 214 | 12/7/2024 |
| 2.0.0 | 208 | 11/26/2024 |
| 1.2.0 | 217 | 10/31/2024 |