Custom Formatter¶
Applications can provide custom formatter implementations when the built-in JSON formatters are not sufficient.
A custom formatter is useful when you need:
- a non-JSON payload format;
- compression;
- encryption;
- custom binary serialization;
- compatibility with an existing protocol.
Implement IDataFormatter¶
A custom formatter must implement IDataFormatter.
Conceptually, a formatter converts:
CLR object -> byte[]
byte[] -> CLR object
Example¶
public sealed class CustomDataFormatter : IDataFormatter
{
public Encoding Encoder { get; } = Encoding.UTF8;
public byte[] Encode<TData>(TData data)
{
var json = JsonSerializer.Serialize(data);
return Encoder.GetBytes(json);
}
public TData Decode<TData>(byte[] data)
{
var json = Encoder.GetString(data);
return JsonSerializer.Deserialize<TData>(json)!;
}
}
Compression Example¶
A custom formatter can wrap another formatter.
public sealed class CompressedDataFormatter(
IDataFormatter innerFormatter)
: IDataFormatter
{
public Encoding Encoder => innerFormatter.Encoder;
public byte[] Encode<TData>(TData data)
{
var payload = innerFormatter.Encode(data);
return Compress(payload);
}
public TData Decode<TData>(byte[] data)
{
var payload = Decompress(data);
return innerFormatter.Decode<TData>(payload);
}
private static byte[] Compress(byte[] data)
{
// Apply compression.
return data;
}
private static byte[] Decompress(byte[] data)
{
// Apply decompression.
return data;
}
}
Registration¶
Register the custom formatter wherever publishers and subscribers are created.
IDataFormatter formatter =
new CustomDataFormatter();
For dependency injection scenarios, register it as the IDataFormatter implementation used by the application.
Compatibility¶
Both sender and receiver must use compatible payload formats.
graph LR
Publisher["Publisher<br/>Custom Formatter"]
Payload["byte[]"]
Subscriber["Subscriber<br/>Compatible Formatter"]
Publisher --> Payload
Payload --> Subscriber
If the receiver cannot decode the payload, message processing will fail.
Best Practices¶
- Keep the payload format stable.
- Version the payload format when necessary.
- Avoid changing serialization rules without migration planning.
- Keep formatter exceptions clear and actionable.
- Test custom formatters with real message contracts.