StackExchange.Redis.Extensions.Utf8Json
12.1.0
dotnet add package StackExchange.Redis.Extensions.Utf8Json --version 12.1.0
NuGet\Install-Package StackExchange.Redis.Extensions.Utf8Json -Version 12.1.0
<PackageReference Include="StackExchange.Redis.Extensions.Utf8Json" Version="12.1.0" />
<PackageVersion Include="StackExchange.Redis.Extensions.Utf8Json" Version="12.1.0" />
<PackageReference Include="StackExchange.Redis.Extensions.Utf8Json" />
paket add StackExchange.Redis.Extensions.Utf8Json --version 12.1.0
#r "nuget: StackExchange.Redis.Extensions.Utf8Json, 12.1.0"
#:package StackExchange.Redis.Extensions.Utf8Json@12.1.0
#addin nuget:?package=StackExchange.Redis.Extensions.Utf8Json&version=12.1.0
#tool nuget:?package=StackExchange.Redis.Extensions.Utf8Json&version=12.1.0
StackExchange.Redis.Extensions
StackExchange.Redis.Extensions is a library that extends StackExchange.Redis, making it easier to work with Redis in .NET applications. It wraps the base library with serialization, connection pooling, and higher-level APIs so you can store and retrieve complex objects without writing boilerplate code.
AI-Ready: This library provides an
llms.txtfile for AI coding assistants and a Claude Code plugin for configuration, scaffolding, and troubleshooting.claude plugin add imperugo/StackExchange.Redis.ExtensionsThen use
/redis-configure,/redis-scaffold, or/redis-diagnosein Claude Code.
Features
- Store and retrieve complex .NET objects with automatic serialization
- Multiple serialization providers (System.Text.Json, Newtonsoft, Protobuf, MsgPack, MemoryPack, and more)
- Connection pooling with LeastLoaded and RoundRobin strategies
- Pub/Sub messaging with typed handlers
- Hash operations with per-field expiry (Redis 7.4+)
- GeoSpatial indexes (GEOADD, GEOSEARCH, GEODIST, etc.)
- Redis Streams with consumer group support
- Set, List, and Sorted Set operations
- Key tagging and search
- Transparent compression (GZip, Brotli, LZ4, Snappy, Zstandard)
- Azure Managed Identity support
- ASP.NET Core integration with DI
- Multiple named Redis instances
- OpenTelemetry integration
- .NET Standard 2.1, .NET 8, .NET 9, .NET 10
Architecture
graph TB
App[Your Application] --> DI[ASP.NET Core DI]
DI --> Factory[IRedisClientFactory]
Factory --> Client1[IRedisClient - Default]
Factory --> Client2[IRedisClient - Named]
Client1 --> DB[IRedisDatabase]
DB --> Pool[Connection Pool Manager]
Pool --> C1[Connection 1]
Pool --> C2[Connection 2]
Pool --> C3[Connection N...]
DB --> Ser[ISerializer]
Ser --> Comp[CompressedSerializer?]
Comp --> Inner[System.Text.Json / Newtonsoft / ...]
C1 --> Redis[(Redis Server)]
C2 --> Redis
C3 --> Redis
Quick Start
1. Install packages
dotnet add package StackExchange.Redis.Extensions.Core
dotnet add package StackExchange.Redis.Extensions.System.Text.Json
dotnet add package StackExchange.Redis.Extensions.AspNetCore
2. Configure in appsettings.json
{
"Redis": {
"Password": "",
"AllowAdmin": true,
"Ssl": false,
"ConnectTimeout": 5000,
"SyncTimeout": 5000,
"Database": 0,
"Hosts": [
{ "Host": "localhost", "Port": 6379 }
],
"PoolSize": 5,
"IsDefault": true
}
}
3. Register in DI
var redisConfig = builder.Configuration.GetSection("Redis").Get<RedisConfiguration>();
builder.Services.AddStackExchangeRedisExtensions<SystemTextJsonSerializer>(redisConfig);
4. Use it
public class MyService(IRedisDatabase redis)
{
public async Task Example()
{
// Store an object
await redis.AddAsync("user:1", new User { Name = "Ugo", Age = 38 });
// Retrieve it
var user = await redis.GetAsync<User>("user:1");
// Store with expiry
await redis.AddAsync("session:abc", sessionData, TimeSpan.FromMinutes(30));
// Bulk operations
var items = new[]
{
Tuple.Create("key1", "value1"),
Tuple.Create("key2", "value2"),
};
await redis.AddAllAsync(items, TimeSpan.FromHours(1));
// Search keys
var keys = await redis.SearchKeysAsync("user:*");
}
}
NuGet Packages
Core
| Package | Description | NuGet |
|---|---|---|
| Core | Core library with abstractions and implementations | |
| AspNetCore | ASP.NET Core DI integration and middleware |
Serializers (pick one)
Compressors (optional)
Usage Examples
Hash Operations
// Set a hash field
await redis.HashSetAsync("user:1", "name", "Ugo");
await redis.HashSetAsync("user:1", "email", "ugo@example.com");
// Get a hash field
var name = await redis.HashGetAsync<string>("user:1", "name");
// Set with per-field expiry (Redis 7.4+)
await redis.HashSetWithExpiryAsync("user:1", "session", sessionData, TimeSpan.FromMinutes(30));
// Query field TTL
var ttl = await redis.HashFieldGetTimeToLiveAsync("user:1", new[] { "session" });
GeoSpatial
// Add locations
await redis.GeoAddAsync("restaurants", new[]
{
new GeoEntry(13.361389, 38.115556, "Pizzeria Da Michele"),
new GeoEntry(15.087269, 37.502669, "Trattoria del Corso"),
new GeoEntry(12.496366, 41.902782, "Da Enzo al 29"),
});
// Distance between two places
var km = await redis.GeoDistanceAsync("restaurants",
"Pizzeria Da Michele", "Trattoria del Corso", GeoUnit.Kilometers);
// Search within 200km of a point
var nearby = await redis.GeoSearchAsync("restaurants", 13.361389, 38.115556,
new GeoSearchCircle(200, GeoUnit.Kilometers),
count: 10, order: Order.Ascending);
Redis Streams
// Publish typed events
await redis.StreamAddAsync("orders", "payload", new Order { Id = 1, Total = 99.99m });
// Consumer group workflow
await redis.StreamCreateConsumerGroupAsync("orders", "processors");
var entries = await redis.StreamReadGroupAsync("orders", "processors", "worker-1");
foreach (var entry in entries)
{
// Process the message
await redis.StreamAcknowledgeAsync("orders", "processors", entry.Id!);
}
Pub/Sub
// Subscribe to typed messages
await redis.SubscribeAsync<OrderEvent>("orders:new", async order =>
{
Console.WriteLine($"New order: {order.Id}");
});
// Publish
await redis.PublishAsync("orders:new", new OrderEvent { Id = 42 });
Compression
// Enable transparent compression with any serializer
services.AddStackExchangeRedisExtensions<SystemTextJsonSerializer>(config);
services.AddRedisCompression<LZ4Compressor>(); // That's it!
// All operations automatically compress/decompress
await redis.AddAsync("large-data", myLargeObject); // stored compressed
var obj = await redis.GetAsync<MyObject>("large-data"); // decompressed automatically
Azure Managed Identity
var config = new RedisConfiguration { /* ... */ };
config.ConfigurationOptionsAsyncHandler = async opts =>
{
await opts.ConfigureForAzureWithTokenCredentialAsync(new DefaultAzureCredential());
return opts;
};
Connection Pooling
graph LR
subgraph Pool["Connection Pool (PoolSize=5)"]
C1["Connection 1<br/>Outstanding: 3"]
C2["Connection 2<br/>Outstanding: 0"]
C3["Connection 3<br/>Outstanding: 7"]
C4["Connection 4<br/>Outstanding: 1"]
C5["Connection 5<br/>Outstanding: 2"]
end
Op["GetConnection()"] -->|LeastLoaded| C2
Op -->|RoundRobin| C4
style C2 fill:#90EE90
style C4 fill:#87CEEB
The pool automatically skips disconnected connections and falls back gracefully when all connections are down, letting StackExchange.Redis's internal reconnection logic recover.
| Strategy | Behavior |
|---|---|
LeastLoaded (default) |
Picks the connected connection with fewest outstanding commands |
RoundRobin |
Random selection among connected connections |
Serialization Behavior
All values stored in Redis go through the configured ISerializer. This means:
- A
stringvalue"hello"is stored as"\"hello\""(JSON-encoded) - Use
IRedisDatabase.Databasefor raw Redis operations without serialization - All serializers follow the same convention:
nullinput produces an empty byte array
Configuration Reference
| Property | Default | Description |
|---|---|---|
Hosts |
Required | Redis server endpoints |
Password |
null |
Redis password |
Database |
0 |
Database index |
Ssl |
false |
Enable TLS |
PoolSize |
5 |
Number of connections in the pool |
ConnectionSelectionStrategy |
LeastLoaded |
Pool selection strategy |
SyncTimeout |
5000 |
Sync operation timeout (ms) |
ConnectTimeout |
5000 |
Connection timeout (ms) |
KeyPrefix |
"" |
Prefix for all keys and channels |
AllowAdmin |
false |
Enable admin commands |
ClientName |
null |
Connection client name |
KeepAlive |
-1 |
Heartbeat interval (seconds). -1 = SE.Redis default, 0 = disabled |
ServiceName |
null |
Sentinel service name |
MaxValueLength |
0 |
Max serialized value size (0 = unlimited) |
WorkCount |
CPU*2 |
I/O threads per SocketManager |
ConnectRetry |
null |
Connection retry count |
CertificateValidation |
null |
TLS certificate validation callback |
CertificateSelection |
null |
TLS client certificate selection callback |
ConfigurationOptionsAsyncHandler |
null |
Async callback for custom ConfigurationOptions setup (e.g. Azure) |
Documentation
Full documentation is available in the doc/ folder:
Getting Started
Configuration
Serializers
Features
- Usage Guide — Add, Get, Replace, Bulk operations
- GeoSpatial Indexes
- VectorSet — AI/ML Similarity Search (Redis 8.0+)
- Redis Streams
- Pub/Sub Messaging
- Hash Field Expiry (Redis 7.4+)
- Compression — GZip, Brotli, LZ4, Snappy, Zstandard
Advanced
- Migration Guide: v11 → v12
- Logging & Diagnostics
- Multiple Redis Servers
- Azure Managed Identity
- OpenTelemetry
- Redis Information Middleware
- NuGet Packages
Contributing
Thanks to all the people who already contributed!
<a href="https://github.com/imperugo/StackExchange.Redis.Extensions/graphs/contributors"> <img src="https://contributors-img.web.app/image?repo=imperugo/StackExchange.Redis.Extensions" /> </a>
Please read CONTRIBUTING.md before submitting a pull request. PRs target the master branch only.
License
StackExchange.Redis.Extensions is Copyright © Ugo Lattanzi and other contributors under the MIT license.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- StackExchange.Redis.Extensions.Core (>= 12.1.0)
- Utf8Json (>= 1.3.7 && < 2.0.0)
-
net10.0
- StackExchange.Redis.Extensions.Core (>= 12.1.0)
- Utf8Json (>= 1.3.7 && < 2.0.0)
-
net8.0
- StackExchange.Redis.Extensions.Core (>= 12.1.0)
- Utf8Json (>= 1.3.7 && < 2.0.0)
-
net9.0
- StackExchange.Redis.Extensions.Core (>= 12.1.0)
- Utf8Json (>= 1.3.7 && < 2.0.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on StackExchange.Redis.Extensions.Utf8Json:
| Package | Downloads |
|---|---|
|
GreatUtilities.Infrastructure
Essencial tools to agile development. |
|
|
JC.NetCore.Cache
JC.NetCore.Cache is a library that extends StackExchange.Redis and Faster allowing you a set of functionality needed by common applications. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 12.1.0 | 41 | 4/11/2026 |
| 12.0.0 | 31 | 4/11/2026 |
| 11.0.0 | 53,698 | 1/20/2025 |
| 10.2.0 | 62,968 | 1/23/2024 |
| 10.1.0 | 5,876 | 1/7/2024 |
| 10.0.2 | 22,579 | 12/25/2023 |
| 10.0.1 | 296 | 12/23/2023 |
| 10.0.0 | 297 | 12/23/2023 |
| 9.1.0 | 32,439 | 3/1/2023 |
| 9.0.0 | 1,460 | 2/20/2023 |
| 8.0.5 | 216,976 | 5/24/2022 |
| 8.0.4 | 26,519 | 2/14/2022 |
| 8.0.3 | 8,809 | 1/14/2022 |
| 8.0.2 | 509 | 1/8/2022 |
| 8.0.1 | 552 | 1/7/2022 |
| 8.0.0 | 508 | 1/7/2022 |
| 7.2.1 | 25,421 | 11/19/2021 |
| 7.1.1 | 29,256 | 6/25/2021 |
| 7.0.1 | 59,970 | 5/21/2021 |
| 7.0.0 | 16,996 | 4/18/2021 |
v12.1.0:
- Added VectorSet API for AI/ML similarity search (Redis 8.0+): VADD, VSIM, VREM, VCONTAINS, VCARD, VDIM, VGETATTR, VSETATTR, VINFO, VRANDMEMBER, VLINKS
- Added llms.txt for AI coding assistant documentation indexing
- Added Claude Code plugin with configure, scaffold, and diagnose skills
- Added complete API reference tables to all feature documentation
- Added SECURITY.md with GitHub Private Vulnerability Reporting
- Added CodeQL Advanced security analysis workflow
- Added CI workflow for automated testing on push/PR
v12.0.0:
- Added .NET 10 target framework
- Added GeoSpatial API (GEOADD, GEOSEARCH, GEODIST, GEOPOS, GEOHASH)
- Added Redis Streams API (XADD, XREAD, XREADGROUP, XACK, consumer groups)
- Added Hash field expiry (HEXPIRE, HSETEX, HPTTL, HPERSIST) for Redis 7.4+
- Added transparent compression support with pluggable ICompressor
- Added compression packages: LZ4, Snappy, Zstandard, GZip, Brotli
- Added Azure Managed Identity support via ConfigurationOptionsAsyncHandler
- Added CertificateSelection, ClientName, KeepAlive configuration properties
- Fixed SyncTimeout default from 1000ms to 5000ms
- Fixed Sentinel CommandMap blocking data commands (EVAL, GET, SET)
- Fixed AddAllAsync TTL race condition (now atomic per key)
- Fixed pool resilience: GetConnection skips disconnected connections
- Fixed PubSub handler silently swallowing exceptions
- Upgraded to StackExchange.Redis 2.12.14
- Upgraded to ConnectAsync (SE.Redis best practice)
- Replaced Moq with NSubstitute