RedisEvents.MessagePack
0.2.20
dotnet add package RedisEvents.MessagePack --version 0.2.20
NuGet\Install-Package RedisEvents.MessagePack -Version 0.2.20
<PackageReference Include="RedisEvents.MessagePack" Version="0.2.20" />
<PackageVersion Include="RedisEvents.MessagePack" Version="0.2.20" />
<PackageReference Include="RedisEvents.MessagePack" />
paket add RedisEvents.MessagePack --version 0.2.20
#r "nuget: RedisEvents.MessagePack, 0.2.20"
#:package RedisEvents.MessagePack@0.2.20
#addin nuget:?package=RedisEvents.MessagePack&version=0.2.20
#tool nuget:?package=RedisEvents.MessagePack&version=0.2.20
RedisEvents.MessagePack
MessagePack-typed publish/consume for RedisEvents, kept in a separate
package for the same reason RedisEvents.Web is: MessagePack
(the MessagePack NuGet package) is a real dependency core must not carry. Reference this only if you
want MessagePack instead of — or alongside — the JSON typed convenience; the core byte-oriented API
needs no serializer at all, and a service can use JSON on one topic and MessagePack on another.
Quickstart
[MessagePackObject]
public sealed record Order([property: Key(0)] string Id, [property: Key(1)] decimal Stake);
public sealed class OrderHandler : IBatchHandler<Order>
{
public ValueTask HandleAsync(ReadOnlyMemory<StreamMsg<Order>> batch, CancellationToken ct)
{
for (var i = 0; i < batch.Length; i++)
{
Order? order = batch.Span[i].Value;
// ... handle it
}
return ValueTask.CompletedTask;
}
}
builder.AddStream<OrderHandler, Order>("orders", MessagePackSerializerOptions.Standard);
Publishing:
builder.AddStreamPublisher("orders");
// later, injected as IStreamPublisher
await publisher.PublishAsync(orderId, order, MessagePackSerializerOptions.Standard, ct: ct);
PublishBatchAsync<T> exists too, plus EnqueueAsync<T> on IStreamBufferedPublisher — the same
three-method shape as the JSON typed convenience in core.
Calling Deserialize<T> directly
IBatchHandler<T>/IMessageHandler<T> above are the recommended path — a handler that only ever
wants T shouldn't have to call a deserialiser itself. Deserialize<T> is the lower-level piece they
are built on, and it is still there directly for a handler that already implements the untyped
IBatchHandler/IMessageHandler — one that filters on StreamMsg.Type itself before deciding how to
decode a message, say, or a topic multiplexing more than one message type:
public sealed class OrderBatchHandler : IBatchHandler
{
public ValueTask HandleAsync(ReadOnlyMemory<StreamMsg> batch, CancellationToken ct)
{
var orders = batch.Deserialize<Order>(MessagePackSerializerOptions.Standard);
for (var i = 0; i < orders.Length; i++)
{
Order? order = orders[i];
// ... handle it
}
return ValueTask.CompletedTask;
}
}
Compression
A published body over 1024 bytes (uncompressed MessagePack encoding) is automatically re-serialised
with LZ4 compression (MessagePackCompression.Lz4BlockArray); a smaller one ships as plain MessagePack
bytes. Decoding needs no special handling either way — Deserialize<T> reads both compressed and
uncompressed bodies transparently, so a consumer never needs to know or care which one a given message
was.
Control it with MessagePackCompressionOptions, passed to any publish call:
// Never compress, regardless of size:
await publisher.PublishAsync(orderId, order, options, compression: MessagePackCompressionOptions.Disabled, ct: ct);
// A different threshold:
await publisher.PublishAsync(orderId, order, options,
compression: new MessagePackCompressionOptions { ThresholdBytes = 4096 }, ct: ct);
Omit compression and MessagePackCompressionOptions.Default applies — enabled, 1024-byte threshold.
Why size-gated at all: MessagePack-CSharp's LZ4 framing has its own fixed overhead, and running the compressor at all costs CPU — worth it for a large payload, wasted on a small one. The library always serialises once uncompressed to measure the actual encoded size, and only pays for a second, compressed serialise pass above the threshold; most messages stay under it and pay for exactly one pass.
AOT note
None of this package's own code uses reflection — MessagePackSerializer.Serialize/Deserialize with
an explicit MessagePackSerializerOptions is all it calls. The caveat is MessagePack-CSharp's own
default resolver, which falls back to runtime code generation (Reflection.Emit) for types it
hasn't seen before — not AOT-safe. For a genuinely AOT-clean app, build your
MessagePackSerializerOptions from MessagePack-CSharp's source-generated resolver (mark your message
types partial with [MessagePackObject]; its own Roslyn generator emits the formatters at compile
time) rather than relying on the default resolver — the same discipline JsonSerializerContext already
asks for on the JSON side of RedisEvents.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- MessagePack (>= 3.1.8)
- RedisEvents (>= 0.2.20)
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 |
|---|---|---|
| 0.2.20 | 80 | 9/21/2026 |
| 0.2.17 | 82 | 9/20/2026 |
| 0.2.16 | 83 | 9/19/2026 |
| 0.2.15 | 85 | 9/18/2026 |
| 0.2.14 | 80 | 9/17/2026 |
| 0.2.13 | 89 | 9/17/2026 |
| 0.2.12 | 89 | 9/17/2026 |
| 0.2.11 | 90 | 9/16/2026 |
| 0.2.9 | 90 | 9/14/2026 |
| 0.2.7 | 89 | 9/14/2026 |
| 0.2.6 | 97 | 9/14/2026 |
| 0.2.3 | 84 | 9/14/2026 |
| 0.2.2 | 87 | 9/14/2026 |
| 0.2.1 | 87 | 9/13/2026 |
| 0.1.27 | 91 | 9/13/2026 |
| 0.1.26 | 81 | 9/13/2026 |
| 0.1.25 | 88 | 9/12/2026 |
| 0.1.24 | 78 | 9/12/2026 |
| 0.1.19 | 83 | 9/12/2026 |
| 0.1.17 | 84 | 9/12/2026 |