Serialization configuration in Orleans

The configuration of serialization in Orleans is a crucial part of the overall system design. While Orleans provides reasonable defaults, you can configure serialization to suit your apps' needs. For sending data between hosts, Orleans.Serialization supports delegating to other serializers, such as Newtonsoft.Json and System.Text.Json. You can add support for other serializers by following the pattern set by those implementations. For grain storage it's best to use IGrainStorageSerializer to configure a custom serializer.

Configure Orleans to use Newtonsoft.Json

To configure Orleans to serialize certain types using Newtonsoft.Json, you must first reference the Microsoft.Orleans.Serialization.NewtonsoftJson NuGet package. Then, configure the serializer, specifying which types it will be responsible for. In the following example, we will specify that the Newtonsoft.Json serializer will be responsible for all types in the Example.Namespace namespace.

siloBuilder.Services.AddSerializer(serializerBuilder =>
{
    serializerBuilder.AddNewtonsoftJsonSerializer(
        isSupported: type => type.Namespace.StartsWith("Example.Namespace"));
});

In the preceding example, the call to AddNewtonsoftJsonSerializer adds support for serializing and deserializing values using Newtonsoft.Json.JsonSerializer. Similar configuration must be performed on all clients that need to handle those types.

For types that are marked with GenerateSerializerAttribute), Orleans will prefer the generated serializer over the Newtonsoft.Json serializer.

Configure Orleans to use System.Text.Json

Alternatively, to configure Orleans to use System.Text.Json to serialize your types, you reference the Microsoft.Orleans.Serialization.SystemTextJson NuGet package. Then, configure the serializer, specifying which types it will be responsible for. In the following example, we will specify that the System.Text.Json serializer will be responsible for all types in the Example.Namespace namespace.

Consider the following example when interacting with the ISiloBuilder:

siloBuilder.Services.AddSerializer(serializerBuilder =>
{
    serializerBuilder.AddJsonSerializer(
        isSupported: type => type.Namespace.StartsWith("Example.Namespace"));
});

External serializer providers

It's important to ensure that serialization configuration is identical on all clients and silos. If configurations are inconsistent, serialization errors may occur.

Serialization providers that implement IExternalSerializer can be specified using the SerializationProviderOptions.SerializationProviders property of ClientConfiguration and GlobalConfiguration in code:

// Client configuration
var clientConfiguration = new ClientConfiguration();
clientConfiguration.SerializationProviders.Add(
    typeof(FantasticSerializer).GetTypeInfo());

// Global configuration
var globalConfiguration = new GlobalConfiguration();
globalConfiguration.SerializationProviders.Add(
    typeof(FantasticSerializer).GetTypeInfo());

Alternatively, they can be specified in XML configuration under the <SerializationProviders /> property of <Messaging>:

<Messaging>
    <SerializationProviders>
        <Provider type="GreatCompany.FantasticSerializer, GreatCompany.SerializerAssembly" />
    </SerializationProviders>
</Messaging>

In both cases, multiple providers can be configured. The collection is ordered, meaning that if a provider which can serialize types A and B is specified before a provider which can only serialize type B, then the latter provider will not be used.

See also