Custom JSON Deserialization in C# with JsonConverter

孤街醉人 提交于 2021-02-11 06:51:10

问题


I have two classes in .Net Core

The class Ownership

namespace CustomStoreDatabase.Models
{
    public class Ownership
    {
        public string OwnershipId { get; set; }
        public List<string> TextOutput { get; set; }
        public DateTime DateTime { get; set; }
        public TimeSpan MeanInterval { get; set; }// Like long ticks, TimeSpan.FromTicks(Int64), TimeSpan.Ticks
    }
}

I need to show MeanInterval like long ticks, using the methods TimeSpan.FromTicks(Int64) and TimeSpan.Ticks.

My custom JsonConverter

using CustomStoreDatabase.Models;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace CustomStoreDatabase.Util
{
    public class OwnershipJSonConverter : JsonConverter<Ownership>
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return true;
        }

        public override Ownership Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.StartObject)
            {
                throw new JsonException();
            }
            //*******************
            // HOW TO IMPLEMENT?
            //*******************
            //throw new NotImplementedException();
        }

        public override void Write(Utf8JsonWriter writer, Ownership value, JsonSerializerOptions options)
        {
            writer.WriteStartObject();
            if (value != null)
            {
                writer.WriteString("OwnershipId", value.OwnershipId);
                writer.WriteString("TextOutput", JsonSerializer.Serialize(value.TextOutput));
                writer.WriteString("DateTime", JsonSerializer.Serialize(value.DateTime));
                if (value.MeanInterval != null)
                {
                    writer.WriteNumber("MeanInterval", (long)value.MeanInterval.Ticks);
                }
                else
                {
                    writer.WriteNull("MeanInterval");
                }
            }
            writer.WriteEndObject();
        }
    }
}

I don't know how to implement the Read method. How can I implement the custom Deserialization overriding the Read method?

If is possible you guys proposal to me another implementation for CanConvert method, I thank you very much.


回答1:


It seems like you only want to perform custom serialization of TimeSpan as it belongs to Ownership, so why not make a converter for TimeSpan only and save yourself from manually serializing all of the other class properties?:

public class TimeSpanConverter : JsonConverter<TimeSpan>
{
    public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return TimeSpan.FromTicks(reader.GetInt64());
    }

    public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
    {
        writer.WriteNumberValue(value.Ticks);
    }
}

Then decorate your MeanInterval property with a JsonConverterAttribute:

public class Ownership
{
    public string OwnershipId { get; set; }
    public List<string> TextOutput { get; set; }
    public DateTime DateTime { get; set; }
    [JsonConverter(typeof(TimeSpanConverter))]
    public TimeSpan MeanInterval { get; set; }// Like long ticks, TimeSpan.FromTicks(Int64), TimeSpan.Ticks
}

Try it online




回答2:


My response (long way), you can choose when apply the custom converter. Others related posts: post1, post2 and doc.

namespace CustomStoreDatabase.Util
{
    public class OwnershipJSonConverter : JsonConverter<Ownership>
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return true;
        }

        public override Ownership Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.StartObject)
            {
                throw new JsonException();
            }
            Ownership value = new Ownership();
            while (reader.Read())
            {
                //Console.WriteLine($"reader.TokenType:{reader.TokenType}");
                if (reader.TokenType == JsonTokenType.EndObject) {
                    //Console.WriteLine($"End Object!");
                    break;
                }
                switch (reader.TokenType)
                {
                    case JsonTokenType.PropertyName:
                        {
                            string propertyName = reader.GetString();
                            //Console.WriteLine($"propertyName:{propertyName}");
                            switch (propertyName)
                            {
                                case "OwnershipId":
                                    {
                                        reader.Read();
                                        if (reader.TokenType != JsonTokenType.Null) {
                                            value.OwnershipId = reader.GetString();
                                        }
                                        break;
                                    }
                                case "TextOutput":
                                    {
                                        reader.Read();
                                        if (reader.TokenType != JsonTokenType.Null)
                                        {
                                            value.TextOutput = JsonSerializer.Deserialize<List<string>>(reader.GetString());
                                        }
                                        break;
                                    }
                                case "DateTime":
                                    {
                                        reader.Read();
                                        if (reader.TokenType != JsonTokenType.Null)
                                        {
                                            value.DateTime = JsonSerializer.Deserialize<DateTime>(reader.GetString());
                                        }
                                        break;
                                    }
                                case "MeanInterval":
                                    {
                                        reader.Read();
                                        if (reader.TokenType != JsonTokenType.Null)
                                        {
                                            value.MeanInterval = TimeSpan.FromTicks(reader.GetInt32());
                                        }
                                        break;
                                    }
                            }
                            break;
                        }
                }
            }
            return value;
        }

        public override void Write(Utf8JsonWriter writer, Ownership value, JsonSerializerOptions options)
        {
            writer.WriteStartObject();
            if (value != null)
            {
                writer.WriteString("OwnershipId", value.OwnershipId);
                writer.WriteString("TextOutput", JsonSerializer.Serialize(value.TextOutput));
                writer.WriteString("DateTime", JsonSerializer.Serialize(value.DateTime));
                if (value.MeanInterval != null)
                {
                    writer.WriteNumber("MeanInterval", (long)value.MeanInterval.Ticks);
                }
                else
                {
                    writer.WriteNull("MeanInterval");
                }
            }
            writer.WriteEndObject();
        }
    }
}

My test

public class Program
{
    public static void Main(string[] args)
    {
        var ownershipI = new Ownership() {
            OwnershipId = "--OwnershipId--",
            TextOutput = new List<string>()
            {
                "carrot",
                "fox",
                "explorer"
            },
            DateTime = DateTime.Now,
            MeanInterval = TimeSpan.FromSeconds(-0.05)
        };

        string jsonStringDefault = JsonSerializer.Serialize(ownershipI, new JsonSerializerOptions{
            WriteIndented = true,
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
        });
        Console.WriteLine($"jsonStringDefault:{jsonStringDefault}");

        var serializeOptions = new JsonSerializerOptions
        {
            WriteIndented = true,
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
            Converters = { new OwnershipJSonConverter() }
        };
        string jsonStringCustomInput = JsonSerializer.Serialize(ownershipI, serializeOptions);
        Console.WriteLine($"jsonStringCustomInput:{jsonStringCustomInput}");
        Console.WriteLine($"Are jsonStringDefault and jsonStringCustomInput Equals?: {jsonStringDefault.Equals(jsonStringCustomInput)}");

        Ownership ownershipO  = JsonSerializer.Deserialize<Ownership>(jsonStringCustomInput, serializeOptions);
        string jsonStringCustomOutput = JsonSerializer.Serialize(ownershipO, serializeOptions);
        Console.WriteLine($"jsonStringCustomOutput:{jsonStringCustomOutput}");

        Console.WriteLine($"Are jsonStringCustomInput and jsonStringCustomOutput Equals?: :{jsonStringCustomInput.Equals(jsonStringCustomOutput)}");
        Console.WriteLine();
    }
}

The output:

jsonStringDefault:{
  "OwnershipId": "--OwnershipId--",
  "TextOutput": [
    "carrot",
    "fox",
    "explorer"
  ],
  "DateTime": "2021-02-08T03:13:47.0472512-05:00",
  "MeanInterval": {
    "Ticks": -500000,
    "Days": 0,
    "Hours": 0,
    "Milliseconds": -50,
    "Minutes": 0,
    "Seconds": 0,
    "TotalDays": -5.787037037037037E-07,
    "TotalHours": -1.388888888888889E-05,
    "TotalMilliseconds": -50,
    "TotalMinutes": -0.0008333333333333334,
    "TotalSeconds": -0.05
  }
}
jsonStringCustomInput:{
  "OwnershipId": "--OwnershipId--",
  "TextOutput": "[\"carrot\",\"fox\",\"explorer\"]",
  "DateTime": "\"2021-02-08T03:13:47.0472512-05:00\"",
  "MeanInterval": -500000
}
Are jsonStringDefault and jsonStringCustomInput Equals?: False
jsonStringCustomOutput:{
  "OwnershipId": "--OwnershipId--",
  "TextOutput": "[\"carrot\",\"fox\",\"explorer\"]",
  "DateTime": "\"2021-02-08T03:13:47.0472512-05:00\"",
  "MeanInterval": -500000
}
Are jsonStringCustomInput and jsonStringCustomOutput Equals?: :True


来源:https://stackoverflow.com/questions/66073750/custom-json-deserialization-in-c-sharp-with-jsonconverter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!