2

I have a request class that has three properties, two of them will be deserialized from json request body and the last one will be created based on the other two properties after deserialization. I am using the OnDeserialized() annotation to achieve this. However, it seems that the OnDeserialized annotation has no effect at all. The following is my code. Please advise!

public class BindUserRequest : IRequest<BindUserResponseDto>
{

    [JsonIgnore]
    public PartitionKeyType Id { get; set; }


    [Required]
    public string DeviceType { get; set; }

    [Required]
    public string DeviceId { get; set; }

    [OnSerializing()]
    void OnSerializingMethod(StreamingContext context)
    {
        DeviceType = Id.DeviceType;
        DeviceId = Id.DeviceId;
    }

    [OnDeserialized()]
    void OnDeserializedMethod(StreamingContext context)
    {
        Id = new PartitionKeyType { DeviceId = "123", DeviceType = "123" };
        System.Console.WriteLine("****OnDeserialized get called");
    }
}
poke
  • 369,085
  • 72
  • 557
  • 602
Origin Jing
  • 109
  • 12
  • I'm guessing that maybe you're used to using JSON.NET but now you're using System.Text.Json (adding appropriate tags would really help here). Anyway, there are some differences between the tow. [This migration documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to?pivots=dotnet-5-0#callbacks) covers the events you mention. – ProgrammingLlama Apr 23 '21 at 01:19
  • Yes, I'm using System.Text.Json. Thank you for your insight! – Origin Jing Apr 23 '21 at 01:22
  • OnSerializing belongs to System.Runtime.Serialization namespace which is binary serilization, this doesnt work with System.Text.Json – Zach Hutchins Apr 23 '21 at 01:23
  • Also note that ASP.NET does not seemingly have anything to do with this question, and I'm not sure what ASP.NET5 is. There's .NET 5, which is different from .NET Core. There ASP.NET Core, which is different from .NET Core and .NET 5. But there's nothing called ASP.NET 5, and in fact the tag info says "Do not use this tag any more"... – Heretic Monkey Apr 23 '21 at 01:23

1 Answers1

3

The issue you're seeing is down to the change from using JSON.NET as the default serializer in ASP.NET Core 2.x to using System.Text.Json in newer versions. With JSON.NET these callbacks can be used, but with System.Text.Json they aren't part of the serialization process.

One solution is to add the appropriate NuGet package and continue using JSON.NET (see this question). Alternatively, Microsoft have produced a migration documentation page for handling the change from JSON.NET to System.Text.Json.

The documentation explains that using the callbacks with System.Text.Json requires writing a custom converter:

In System.Text.Json, you can simulate callbacks by writing a custom converter. The following example shows a custom converter for a POCO. The converter includes code that displays a message at each point that corresponds to a Newtonsoft.Json callback.

The following sample code is provided:

public class WeatherForecastCallbacksConverter : JsonConverter<WeatherForecast>
{
    public override WeatherForecast 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.
        WeatherForecast forecast = JsonSerializer.Deserialize<WeatherForecast>(ref reader);

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

        return forecast;
    }

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

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

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

You can then add extra serialization code in here to handle your use case. Note that this will either need to be registered on the class itself using the [JsonConverter(type)] attribute, or by registering it with the serializer's Converters collection.

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86