Description
The How to write custom converters for JSON serialization (marshalling) in .NET
page explains how to use default system converter here.
What is not clear is that these converters are only for primitive types. I was hoping this article will explain how I can do this with my own custom built-in types, but it doesn't.
Following example is given for using a default converter in a custom converter:
public class MyCustomConverter : JsonConverter<int>
{
private readonly static JsonConverter<int> s_defaultConverter =
(JsonConverter<int>)JsonSerializerOptions.Default.GetConverter(typeof(int));
// Custom serialization logic
public override void Write(
Utf8JsonWriter writer, int value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
// Fall back to default deserialization logic
public override int Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return s_defaultConverter.Read(ref reader, typeToConvert, options);
}
}
but this doesn't work if value
is not int
but a custom type. The custom converter will be null and just doing value.ToString()
won't produce the right value. Instead, for serialization one has to do:
public override void Write(Utf8JsonWriter writer, MyType value, JsonSerializerOptions options)
{
writer.WriteRawValue(JsonSerializer.Serialize(value));
}
Similarly, for deserialization:
public override MyType? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return JsonSerializer.Deserialize<MyType>(ref reader);
}
Additional context
You might ask: why I am trying to write a custom type converter for a complex type in the first place? Performance will take a hit.
This is an excellent question. It is because of this limitation:
Quote:
Even though not all reference preservation scenaria contain cycles, it arguably is the raison d'etre of the feature. While we could try to make the feature smarter and only fail if cycles are detected, this would require substantially more state to track correctly and it would impact performance. Consequently, explicitly not supporting the feature at all for constructor deserialization is the right apprioach in my view. As you mention, the workaround is to simply refactor constructor parameters to be init or required properties.
In addition, the documentation on ReferenceHandler.Preserve says:
This feature can't be used to preserve value types or immutable types. On deserialization, the instance of an immutable type is created after the entire payload is read. So it would be impossible to deserialize the same instance if a reference to it appears within the JSON payload.
I am trying to implement my own serialization that will preserve all references and also use constructors, without using required
or init
properties. This is because I want to forbid using an object initializer because I want to ensure constructor is called, as I am going to put precondition checks in the constructor which would be circumvented otherwise.
Hence, if I could write a custom converter for my complex type I would make it know when to serialize its members fully and when just by reference, to avoid cycles and duplication. It would also have matching deserialization logic which knows when to deserialize given object and when to deserialize just a reference to it and call proper constructors in the right order.
@eiriktsarpalis if you perhaps have some insight how to best deal with my scenario I would be grateful. Maybe there is better approach than what I am thinking.
Related:
- Code snippet in
Consume decoded JSON strings
inHow to use a JSON document, Utf8JsonReader, and Utf8JsonWriter in System.Text.Json
does not compile #35019 - The documentation on using
Utf8JsonReader
should explain how to obtain different kinds of objects from it, like e.g.JsonNode
. #35021
Document Details
⚠ Do not edit this section. It is required for learn.microsoft.com ➟ GitHub issue linking.
- ID: 5de37d79-751f-e372-e866-efde28f4908c
- Version Independent ID: 678c4f23-764a-7ccd-0d6d-159a30957477
- Content: How to write custom converters for JSON serialization - .NET
- Content Source: docs/standard/serialization/system-text-json/converters-how-to.md
- Product: dotnet-fundamentals
- GitHub Login: @gewarren
- Microsoft Alias: gewarren