C
C#13mo ago
Owez

Implementing JsonConverter to simplify Ser/De

I've been trying to implemement a JsonConverter for a simple class to simplify the default C# tagging using JsonSerializer. Here's the class I'm trying to convert:
public class Snapshot<T>
{
public DateTime Taken { get; set; }
public T Data { get; set; }

public static Snapshot<T> NewEmpty()
{
return new Snapshot<T>
{
Taken = DateTime.MinValue,
Data = default
};
}
}
public class Snapshot<T>
{
public DateTime Taken { get; set; }
public T Data { get; set; }

public static Snapshot<T> NewEmpty()
{
return new Snapshot<T>
{
Taken = DateTime.MinValue,
Data = default
};
}
}
And here's an example serialized output for what I need:
{"2020-06-21T00:00:00":"this is some data here!!"}
{"2020-06-21T00:00:00":"this is some data here!!"}
(FYI the default serializer outputs {"Taken":"2020-06-21T00:00:00","Data":"this is some data here!!"}). How do I implement a JsonConverter to Read & Write to my desired format? I need the generics to always work and this Snapshot will be used as an attribute of a parent class I've wrote this so far which feels like it's going in the right direction, but I'm not sure if the JsonSerializer line here is right and I'm not sure about how to implement Read:
public class SnapshotConverter<T> : JsonConverter<Snapshot<T>>
{
public override Snapshot<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException("Deserialization is not supported.");
}

public override void Write(Utf8JsonWriter writer, Snapshot<T> value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName(value.Taken.ToString("s"));
JsonSerializer.Serialize(writer, value.Data, options);
writer.WriteEndObject();
}
}
public class SnapshotConverter<T> : JsonConverter<Snapshot<T>>
{
public override Snapshot<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException("Deserialization is not supported.");
}

public override void Write(Utf8JsonWriter writer, Snapshot<T> value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName(value.Taken.ToString("s"));
JsonSerializer.Serialize(writer, value.Data, options);
writer.WriteEndObject();
}
}
2 Replies
Squidgy
Squidgy13mo ago
This doesn't necessarily answer your question since you specifically asked about JsonConverter.. But one way to go about it is to use a Dictionary, e.g. implement a method like this in your Snapshot class:
public string SerializeToJson(Snapshot<T> snapshot)
{
var dictionary = new Dictionary<DateTime, T>
{
{ snapshot.Taken, snapshot.Data }
};

return JsonSerializer.Serialize(dictionary);
}
public string SerializeToJson(Snapshot<T> snapshot)
{
var dictionary = new Dictionary<DateTime, T>
{
{ snapshot.Taken, snapshot.Data }
};

return JsonSerializer.Serialize(dictionary);
}
Then you can call it like this:
var snapshot = new Snapshot<string>
{
Taken = new DateTime(2022, 06, 21),
Data = "this is some data here!!"
};

var json = snapshot.SerializeToJson(snapshot);
// {"2022-06-21T00:00:00":"this is some data here!!"}
var snapshot = new Snapshot<string>
{
Taken = new DateTime(2022, 06, 21),
Data = "this is some data here!!"
};

var json = snapshot.SerializeToJson(snapshot);
// {"2022-06-21T00:00:00":"this is some data here!!"}
Perhaps the same approach could be used inside your SnapshotConverter
Owez
Owez13mo ago
It wont work because I'm not calling serialize specifically on Snapshot, im doing it in a class with contains another class which contains a Snapshot I'll repost because its been many hours on this thread :)