On one of my classes I would like to do some post-deserialization processing.
The naive solution is
[JsonConverter(typeof(MyClassFormatter))]
public class MyClass {
internal void PostSerialisation()
{
//do stuff
}
}
public class MyClassFormatter : JsonConverter<MyClass>
{
public override MyClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var result = JsonSerializer.Deserialize<MyClass>(ref reader, options);
result.PostSerialisation();
return result;
}
public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, options);
}
}
This does not work, obviously, because it is recursive. As I have attached my converter to the class, when I call JsonSerializer.Serialize(...) or JsonSerializer.Deserialize my customer formatter is called and well, you can see where this is going.
Does anyone know of a way of calling JsonSerializer.Serialize or JsonSerializer.Deserialize that ignores my custom formatter and does the default serialization or deserialization?
Of course I could re-implement the serialization/deserialization code but it seems likely that there must be a more elegant solution. This must be quite a common scenario.
CodePudding user response:
Commenter dbc confirmed what I think I had already discovered, that once you have attached a custom converter to a class this problem is difficult to avoid.
However the same commenter pointed out that I was asking the wrong question, and that instead of a custom converter I should implement IJsonOnDeserialization, which worked well.
CodePudding user response:
As far as I know as of .NET 6 there's no way to get the default serialization one you have attached a JsonConverter
to the class itself. The serializer will always use the converter when serializing or deserializing. See
How to use default serialization in a custom System.Text.Json JsonConverter? for confirmation.
However, in your example it appears you only want to call some postprocessing method after serialization is complete:
public override MyClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var result = JsonSerializer.Deserialize<MyClass>(ref reader, options);
result.PostSerialisation();
return result;
}
This can be done in .NET 6 and later without needing a converter by implementing the IJsonOnDeserialized
interface:
public class MyClass : IJsonOnDeserialized
{
void IJsonOnDeserialized.OnDeserialized() => PostSerialisation();
internal void PostSerialisation()
{
//do stuff
}
}
This interface is one of 4 interfaces that, when implemented, cause a callback to be made before or after serialization or deserialization. They are a replacement for Newtonsoft's serialization callbacks:
IJsonOnSerializing
: Specifies that the type should have itsOnSerializing()
method called before serialization occurs.IJsonOnSerialized
: Specifies that the type should have itsOnSerialized()
method called after serialization occurs.IJsonOnDeserializing
: Specifies that the type should have itsOnDeserializing()
method called before deserialization occurs.IJsonOnDeserialized
: Specifies that the JSON type should have itsOnDeserialized()
method called after deserialization occurs.
Note that all four interfaces have the following restriction:
This behavior is only supported on types representing JSON objects. Types that have a custom converter or represent either collections or primitive values do not support this behavior.
Demo fiddle here: https://dotnetfiddle.net/42uzer.