Skip to content

RPC Serialization Formats

ActualLab.Rpc supports multiple serialization formats with automatic version negotiation between clients and servers. This enables gradual upgrades and interoperability between different Fusion versions.

Overview

RPC serialization has two layers:

  1. Argument serialization: How method arguments are encoded
  2. Message serialization: How RPC messages (containing arguments) are framed

Each combination of these is packaged as an RpcSerializationFormat.

Available Formats

Text Formats (JSON)

FormatKeyDescription
SystemJsonV5json5System.Text.Json with V4 arguments, V3 messages
NewtonsoftJsonV5njson5Newtonsoft.Json with V4 arguments, V3 messages

Binary Formats (MemoryPack)

FormatKeyDescription
MemoryPackV5mempack5V4 args, V4 messages
MemoryPackV5Cmempack5cCompact variant of V5
MemoryPackV6mempack5V4 args, V5 messages
MemoryPackV6Cmempack5cCompact variant of V5

Binary Formats (MessagePack)

FormatKeyDescription
MessagePackV5msgpack5V4 args, V4 messages
MessagePackV5Cmsgpack5cCompact variant of V5
MessagePackV6msgpack5V4 args, V5 messages
MessagePackV6Cmsgpack5cCompact variant of V5

Binary Formats (Nerdbank.MessagePack)

These formats require the ActualLab.Serialization.NerdbankMessagePack package. They are not registered by default — call RpcNerdbankSerializationFormat.Register() at startup to enable them.

FormatKeyDescription
NerdbankMessagePackV6nmsgpack6Nerdbank.MessagePack, V4 args, V5 messages
NerdbankMessagePackV6Cnmsgpack6cCompact variant of V6

Format Selection

Default Format

The default format is typically MemoryPackV5C (or latest version) for .NET 6+ and MessagePackV5C for .NET Standard.

Client-Server Negotiation

When a client connects, it requests its preferred serialization format via a URL parameter (e.g., <endpoint>?f=msgpack6&clientId=...). The server accepts the connection if it supports that format. Once connected, both parties simultaneously exchange RpcHandshake messages:

Client-Server Negotiation

Accessing All Formats

cs
// All registered formats
ImmutableList<RpcSerializationFormat> all = RpcSerializationFormat.All;

// Find by key
var format = RpcSerializationFormat.All.First(f => f.Key == "mempack6c");

Format Structure

Each RpcSerializationFormat consists of:

cs
public sealed class RpcSerializationFormatExample(
    string key,
    Func<RpcArgumentSerializer> argumentSerializerFactory,
    Func<RpcPeer, RpcMessageSerializer> messageSerializerFactory)
{
    public string Key { get; } = key;
    public RpcArgumentSerializer ArgumentSerializer { get; } = argumentSerializerFactory();
    public Func<RpcPeer, RpcMessageSerializer> MessageSerializerFactory { get; } = messageSerializerFactory;
}
PropertyDescription
KeyUnique string identifier for negotiation
ArgumentSerializerSerializes method arguments
MessageSerializerFactoryCreates message serializers per peer

Version Differences

Argument Serializer Versions

VersionDescription
V4Latest, best performance

Message Serializer Versions

VersionVariantsDescription
V4Normal, CompactWas optimal up to Fusion v11.5.X
V5Normal, CompactSaves 1 byte per message over V4

Compact vs Normal

Compact variants (*C suffix) use smaller message framing at a slight CPU cost. Choose compact for:

  • Lower bandwidth scenarios
  • When message overhead is significant relative to payload

Configuring Formats

Enabling Nerdbank.MessagePack Formats

Add the ActualLab.Serialization.NerdbankMessagePack package and call Register() at startup:

cs
// Register nmsgpack6 / nmsgpack6c formats
RpcNerdbankSerializationFormat.Register();

Registering Additional Formats

cs
RpcSerializationFormat.All = RpcSerializationFormat.All.Add(
    new RpcSerializationFormat(
        "custom",
        () => new MyArgumentSerializer(),
        peer => new MyMessageSerializer(peer)));

Removing Formats

To disable older formats for security:

cs
// To disable older formats for security:
RpcSerializationFormat.All = RpcSerializationFormat.All
    .RemoveAll(f => f.Key.StartsWith("mempack5") || f.Key.StartsWith("msgpack5"));

Format Selection Factors

When choosing formats, consider:

FactorRecommendation
PerformanceBinary formats (MemoryPack > MessagePack > JSON)
DebuggingJSON formats (human-readable)
CompatibilityMessagePack for .NET Standard clients
BandwidthCompact variants (*C)
SecurityLatest versions, disable V1

Serialization in RPC Pipeline

Serialization in RPC Pipeline
  1. Client serializes method arguments using ArgumentSerializer
  2. Arguments are wrapped in an RpcMessage and serialized by MessageSerializer
  3. Binary data is sent over WebSocket
  4. Server deserializes in reverse order