Serialization
The Memory, Redis and SQL Server caches store byte[]. IObjectSerialization converts the
objects you put in a cache to bytes and back. Since Arc4u 9 the only format shipped is JSON with System.Text.Json, plain
or compressed. This page extends the caching guide.
What it solves
You call cache.Put("key", order) and cache.Get<Order>("key"); the cache serializes for you, even the memory cache.
Arc4u keeps the format behind a small interface, so you can:
- keep the default JSON, or set your own
JsonSerializerOptions; - compress large values (GZip, Deflate, Brotli or Zip);
- use a source-generated
JsonSerializerContext, which does not need reflection (for trimming and Native AOT); - give each cache its own serializer.
The Dapr cache does not use this interface: the Dapr client serializes the values itself. For trimming
and Native AOT, give it a JsonSerializerContext through its options, see
Dapr.
Packages involved
| Package | Use it for |
|---|---|
Arc4u.Serializer |
The IObjectSerialization interface. No dependency. |
Arc4u.Serializer.JSon |
JsonSerialization and the compressed variants. Uses System.Text.Json and Microsoft.IO.RecyclableMemoryStream. |
Install
dotnet add package Arc4u.Serializer.JSon --prerelease
Configuration
The serializers have no configuration section. You register them in the service collection, and a cache selects one with
the SerializerName setting of its Settings.
The interface
IObjectSerialization has three members:
| Member | Description |
|---|---|
byte[] Serialize<T>(T value) |
Converts the value to bytes. |
T? Deserialize<T>(byte[] data) |
Converts the bytes to a T. |
object? Deserialize(byte[] data, Type objectType) |
Same, when the type is known at run time only. |
The implementations
All are in the Arc4u.Serializer namespace.
| Class | Format |
|---|---|
| JsonSerialization | UTF-8 JSON. |
| JsonGZipSerialization | JSON compressed with GZip (fastest level). |
| JsonDeflateSerialization | JSON compressed with Deflate (fastest level). |
| JsonBrotliSerialization | JSON compressed with Brotli (fastest level). |
| JsonZipSerialization | A Zip archive with one entry, content, that holds the JSON. |
Each class has three constructors:
| Constructor | Use it for |
|---|---|
() |
The default JsonSerializerOptions of System.Text.Json. Reflection based. |
(JsonSerializerOptions options) |
Your own options (naming policy, converters). Reflection based. |
(JsonSerializerContext context) |
A source-generated context. No reflection: use it when you trim or publish with Native AOT. |
The first two are marked RequiresUnreferencedCode and show trimming warnings in a trimmed or AOT project. The exception
is JsonZipSerialization, whose context constructor is also marked RequiresUnreferencedCode: for trimming or Native AOT,
use JsonSerialization, JsonGZipSerialization, JsonDeflateSerialization or JsonBrotliSerialization with a context.
Code
Register one unkeyed serializer, which every cache uses unless it names another one, and optional keyed serializers:
// Program.cs
using System.Text.Json;
using Arc4u.Serializer;
var builder = WebApplication.CreateBuilder(args);
// Used by the caches without a SerializerName.
builder.Services.AddSingleton<IObjectSerialization>(
_ => new JsonSerialization(new JsonSerializerOptions(JsonSerializerDefaults.Web)));
// Used by the caches with "SerializerName": "gzip".
builder.Services.AddKeyedSingleton<IObjectSerialization>("gzip", (_, _) => new JsonGZipSerialization());
var app = builder.Build();
app.Run();
Then select the keyed serializer in the configuration of a cache:
{
"Caching": {
"Default": "Volatile",
"Caches": [
{
"Name": "Volatile",
"Kind": "Memory",
"IsAutoStart": true,
"Settings": {
"SizeLimitInMB": 50,
"SerializerName": "gzip"
}
}
]
}
}
A cache resolves its serializer when it is initialized: the keyed one named by SerializerName, otherwise the unkeyed one.
A SerializerName that is not registered falls back to the unkeyed serializer without an error. When neither exists, the
cache stays uninitialized and its operations throw CacheNotInitializedException.
Common scenarios
Use a source-generated context
using System.Text.Json.Serialization;
using Arc4u.Serializer;
public record Product(string Id, string Name);
[JsonSerializable(typeof(Product))]
public partial class AppJsonContext : JsonSerializerContext
{
}
public static class AotSerializer
{
public static IObjectSerialization Create() => new JsonSerialization(AppJsonContext.Default);
}
The context must list every type you put in the cache, otherwise System.Text.Json throws at run time.
Serialize outside a cache
The serializers are ordinary objects:
using Arc4u.Serializer;
public static class RoundTrip
{
public static Product? Copy(Product product)
{
IObjectSerialization serializer = new JsonSerialization();
byte[] bytes = serializer.Serialize(product);
return serializer.Deserialize<Product>(bytes);
}
}
Extensibility points
| Service | Default implementation | Replace it to |
|---|---|---|
| IObjectSerialization | none: you register JsonSerialization or a variant |
Use another format. Implement the three members and register the class, unkeyed or keyed. |
Data written with one serializer cannot be read with another: change the serializer of a shared cache (Redis, SQL Server)
only when the cache is empty or its entries can be lost. The serializers set the SerializerType tag on the current
Activity, so a trace shows which one ran.
Troubleshooting
Values come back as null or Get throws DataCacheException after a change of serializer
The bytes in the store were written by a different serializer or different options. Clear the cache or change the
InstanceName, TableName or the cache name.
NotSupportedException or missing properties with a source-generated context
The type, or one of its members, is not registered in the JsonSerializerContext. Add a [JsonSerializable] attribute for it.
Where are the Newtonsoft.Json, Protobuf and BSON serializers?
They were removed in Arc4u 9. See Newtonsoft.Json replaced by System.Text.Json and ADAL and Protobuf removed.
See also
- Caching
- Migrate from 8.x to 9
- Arc4u.Serializer in the API reference