Using System.Text.Json Source Generator to Improve Performance

Overview

This blog post shows how you can improve JSON serialization performance with a simple step, thanks to the Roslyn Source Generator feature.

Source Generators

Source generators are Roslyn plugins that can write tedious code for you, either C# or VB. Here I will use C#.

When it comes down to JSON serialization, the JsonSerializer.Serialize method will use reflection to figure out the meta-data it needs to serialize and deserialize a certain type. You can speed up this process by supplying the meta-data yourself, but this results in a lot of boring code, and who wants to write this kind of repetetive code?

Generating Serialization Meta-data using a Source Generator

You can automate this meta-data code using a source generator.

Start by creating a class deriving from JsonSerializerContext, and add the JsonSerializable attribute:

[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Person))]
internal partial class PersonJsonSerializerContext : JsonSerializerContext
{
}

Hit compile, and this will now generate the code! That's it!

Examining the generated code

If you like you can examine the generated code. Start by adding the <EmitCompilerGeneratedFiles> option to your project.

<PropertyGroup>
  <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>

You can now find the generated code in

obj
  \Debug
    \net*.0
      \generated
        \System.Text.Json.SourceGeneration
          \System.Text.Json.SourceGeneration.JsonSourceGenerator

Using the generated meta-data

You can now use the generated meta-data by passing it to the serializer:

Person person = new() { ... };
string Json = JsonSerializer.Serialize(person, PersonJsonSerializerContext.Default.Person);
Person p = JsonSerializer.Deserialize(Json, PersonJsonSerializerContext.Default.Person);

What about changes in the code?

When you make changes to your Person class, the source generator will regenerate all the code.