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
SystemJsonV3json3System.Text.Json with V3 argument/message serialization
SystemJsonV5json5System.Text.Json with V4 arguments, V3 messages
NewtonsoftJsonV3njson3Newtonsoft.Json with V3 argument/message serialization
NewtonsoftJsonV5njson5Newtonsoft.Json with V4 arguments, V3 messages

Binary Formats (MemoryPack)

FormatKeyDescription
MemoryPackV1mempack1Legacy V1 format
MemoryPackV2mempack2V2 args with forced polymorphism
MemoryPackV2Cmempack2cCompact variant of V2
MemoryPackV3mempack3V3 arguments
MemoryPackV3Cmempack3cCompact variant of V3
MemoryPackV4mempack4V3 args, V4 messages
MemoryPackV4Cmempack4cCompact variant of V4
MemoryPackV5mempack5V4 args, V4 messages
MemoryPackV5Cmempack5cCompact variant of V5

Binary Formats (MessagePack)

FormatKeyDescription
MessagePackV1msgpack1Legacy V1 format
MessagePackV2msgpack2V2 args with forced polymorphism
MessagePackV2Cmsgpack2cCompact variant of V2
MessagePackV3msgpack3V3 arguments
MessagePackV3Cmsgpack3cCompact variant of V3
MessagePackV4msgpack4V3 args, V4 messages
MessagePackV4Cmsgpack4cCompact variant of V4
MessagePackV5msgpack5V4 args, V4 messages
MessagePackV5Cmsgpack5cCompact variant of V5

Non-Polymorphic Variants

Some formats have -np (non-polymorphic) variants that skip type decoration:

FormatKey
MemoryPackV2NPmempack2-np
MemoryPackV2CNPmempack2c-np
MessagePackV2NPmsgpack2-np
MessagePackV2CNPmsgpack2c-np

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 sends its supported formats. The server selects the best matching format:

Accessing All Formats

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

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

Format Structure

Each RpcSerializationFormat consists of:

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

Version Differences

Argument Serializer Versions

VersionDescription
V1Original format, forced polymorphism
V2Improved with optional polymorphism
V3Optimized encoding
V4Latest, best performance

Message Serializer Versions

VersionVariantsDescription
V3Normal, CompactStandard message framing
V4Normal, CompactImproved framing

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

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("mempack1") || f.Key.StartsWith("msgpack1"));

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

  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