1

I am attempting to have my object execute some logic immediately after deserialization. I am using the example shown on the following Microsoft documentation

The issue that I'm running into is that calling JsonSerializer.Deserialize() results in an infinite recursion loop because Deserialize() is called in the Read override. I know that I can get around this by implementing my own deserialize method - but that defeats the purpose of using this override, so I'm assuming that there's gotta be some way to keep the Deserialize() call in the Read override.

My deserialization test

    public void TestSerializationConverterCallbacks()
    {
        Animal a = JsonSerializer.Deserialize<Animal>(SerializedData.SerializedAnimal);
    }

My serialized object

    [JsonConverter(typeof(AnimalCallbacksConverter))]
    public class Animal
    {
        public string Name { get; set; } = "dog";
        
        public string Id { get; set; } = "123";
    }

My custom Serializer

    public class AnimalCallbacksConverter : JsonConverter<Animal>
    {
        public override Animal Read(
            ref Utf8JsonReader reader,
            Type type,
            JsonSerializerOptions options)
        {
            // Place "before" code here (OnDeserializing),
            // but note that there is no access here to the POCO instance.
            Console.WriteLine("OnDeserializing");

            // Don't pass in options when recursively calling Deserialize.
            Animal animal = JsonSerializer.Deserialize<Animal>(ref reader);

            // Place "after" code here (OnDeserialized)
            Console.WriteLine("OnDeserialized");

            return animal;
        }

        public override void Write(
            Utf8JsonWriter writer,
            Animal animal, JsonSerializerOptions options)
        {
            // Place "before" code here (OnSerializing)
            Console.WriteLine("OnSerializing");

            // Don't pass in options when recursively calling Serialize.
            JsonSerializer.Serialize(writer, animal);

            // Place "after" code here (OnSerialized)
            Console.WriteLine("OnSerialized");
        }
    }
Chris Phillips
  • 1,997
  • 2
  • 19
  • 34
  • You may want to clarify what you expect to achieve with calling Deserialize inside Read. – Alexei Levenkov Jan 30 '23 at 22:51
  • @AlexeiLevenkov You still need to return an object of type `Animal`. It doesn't make sense to completely rewrite the deserializer, so I'm calling Deserialize. My understanding of the documentation is that adding the `[JsonConverter(typeof(AnimalCallbacksConverter))]` attribute to the class should prevent this recursive loop from happening. The documentation for this override also includes Deserialize in the example. – Chris Phillips Jan 30 '23 at 23:25
  • You mean https://stackoverflow.com/questions/65430420/how-to-use-default-serialization-in-a-custom-system-text-json-jsonconverter? – Alexei Levenkov Jan 30 '23 at 23:34

1 Answers1

1

You can use actual deserialization callbacks...

public class MyObject : IJsonOnDeserialized
{
    public MyProperty1 { get; set; }
    public MyProperty2 { get; set; }

    void IJsonOnDeserialized.OnDeserialized()
    {
        //Code runs after deserialization is complete
    }
}

System.Text.Json has an example of this about 2/3rds the way down the page. Newtonsoft.Json doesn't have the limitations that System.Text.Json has, and can use [OnDeserializing] and [OnDeserialized] attributes that take a streaming context.

Ron Beyer
  • 11,003
  • 1
  • 19
  • 37