How does one map an array with indices to an object with a custom JsonConverter

137 views Asked by At

I've seen a couple questions regarding what I'm trying to do, however they seem to be using JSON.Net which is something I don't want to use as .NET Core / .NET 5 has a JsonSerializer built in.

I'm calling an API for HTTP RPC for RuTorrent that responds with a dictionary <string, string[]>. What I'm trying to do is map the indices of this string array to an object instead.

An example of a response from PostMan;

{
    "t": {
        "4CBF8EFCF0797955A7CA79A3CE85D81C8F8B851C": [
            "1",
            "0",
            "1",
            "1",
            "Torrent One",
            "4113182720",
            "1962",
            "1962",
            "4113182720",
            "0",
            "0",
            "0",
            "0",
            "2097152",
            "",
            "0",
            "0",
            "0",
            "0",
            "0",
            "2",
            "1606214313",
            "0",
            "0",
            "1962",
            "/downloads/",
            "0",
            "1",
            "1",
            "",
            "",
            "1282428129280",
            "1",
            "1"
        ],
        "C439916345971D344290D4D5E1F813E3BA37873C": [
            "1",
            "0",
            "1",
            "1",
            "Torrent Two",
            "13072611982",
            "24935",
            "24935",
            "13072611982",
            "7661161341",
            "586",
            "0",
            "0",
            "524288",
            "",
            "0",
            "0",
            "0",
            "0",
            "0",
            "2",
            "1606214313",
            "0",
            "0",
            "24935",
            "/downloads",
            "1353858437",
            "1",
            "1",
            "",
            "",
            "1282428129280",
            "1",
            "1"
        ]
    }
}

Here are my models so far;

public class Result
{
    [JsonPropertyName("t")]
    public IDictionary<string, Torrent> Torrents { get; set; }
    
    public int cid { get; set; }
}

[JsonConverter(typeof(TorrentConverter<String>))]
public class Torrent
{
    public string TorrentName { get; set; }
}

This is all I have so far in my converter (note that .Dump() is a method you can use in the program LinqPad to dump the contents of the object to the window):

public class TorrentConverter<String> : JsonConverter<Torrent>
{   
    public override Torrent Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        reader.GetString().Dump();
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, Torrent value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

I'm unsure what to do exactly with the Utf8JsonReader param. So far I have tried deserializing and .GetString() however it keeps throwing a JsonException with the following:

The JSON value could not be converted to System.Collections.Generic.Dictionary`2[System.String,UserQuery+Torrent]. Path: $.t.4CBF8EFCF0797955A7CA79A3CE85D81C8F8B851C | LineNumber: 0 | BytePositionInLine: 50.

Can someone please point me in the right direction or point out what I'm doing wrong?

Thanks.

1

There are 1 answers

0
Owen On

Turns out I misunderstood what the reader actually was. This contains a JSON blob of the array and I wasn't passing the ref of the reader.

The correct solution was like so...

Models:

public class Result
{
    [JsonPropertyName("t")]
    public IDictionary<string, Torrent> Torrents { get; set; }
    
    public int cid { get; set; }
}

[JsonConverter(typeof(TorrentConverter))]
public class Torrent
{
    public Torrent(IEnumerable<string> data)
    {
        TorrentName = data.ElementAt(4);
    }
    
    public string TorrentName { get; set; }
}

JsonConverter:

public class TorrentConverter : JsonConverter<Torrent>
{
    public override Torrent Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var blob = JsonSerializer.Deserialize<string[]>(ref reader);

        return new Torrent(blob);
    }

    public override void Write(Utf8JsonWriter writer, Torrent value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}