Custom JSON Deserialization in C# with JsonConverter
Asked Answered
H

1

4

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.

Hebrews answered 6/2, 2021 at 5:2 Comment(2)
Can you modify your Ownership model to add System.Text.Json attributes, or is the model effectively read-only for the purposes of this question?Indefinite
@Indefinite Preferably it is better not to modify the class, because for one use I have to get a JSON format, for another use another JSON format. If I change the class to set a single JSON format, it couldn't set the other JSON format.Hebrews
B
5

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

Berliner answered 6/2, 2021 at 5:52 Comment(2)
Hi, John, Thanks´a lot!, Great answer. But unfortunately I removed another class with TimeSpan property, https://mcmap.net/q/35867/-storing-custom-class-property-like-string-via-onmodelcreating-of-dbcontext-net-core/5113188,I need to apply it specifically as a property of the Ownership class, because another Owner class has another property of TimeSpan. Checking the System.Text.Json.Serialization.Json JsonConverter<T> class only contains CanConvert, Read and Write methods..Hebrews
@QA_Col See this fiddle for an updated example of how this works when you use it. You can see that only properties with the attribute applied are affected by the converter. I've also corrected my answer to System.Text.Json instead of Json.NET (my mistake before, sorry).Berliner

© 2022 - 2024 — McMap. All rights reserved.