Search code examples
c#json-deserializationsystem.text.json

C# class mapping for System.Text.Json deserialization


I am writing C# to interface with a third party API. I'm having issues mapping a particular response to a class.

The doco for the method says the response will be:

{
    <text>:[{   /* driver ID */
        "t":<uint>, /* time of binding/unbinding*/
        "u":<long>  /* unit ID if binding, 0 if unbinding */
    }],
    ...
}

An example of the response is: {"2534":[{"t":1711353044,"u":10568}]}. I've defined the Response class and the subclass as:

public class GetDriverBindingsResponse : IWialonApiRequestObject
{
    /// <summary>
    /// Collection of bindings.  The key is a Driver Id
    /// </summary>
    [JsonPropertyName("")]
    public Dictionary<string, List<DriverUnitBinding>>? Bindings { get; set; }
}

public class DriverUnitBinding
{
    /// <summary>
    /// time of binding/unbinding
    /// </summary>
    [JsonPropertyName("t")]
    public uint Time { get; set; }

    /// <summary>
    /// unit ID if binding, 0 if unbinding
    /// </summary>
    [JsonPropertyName("u")]
    public long UnitId { get; set; }
}

However, when deserializing, the Bindings collection is null. Even a simple test fails:

string test = "{\"2534\":[{\"t\":1711353044,\"u\":10568}]}";
GetDriverBindingsResponse? x = JsonSerializer.Deserialize<GetDriverBindingsResponse>(test);
Console.WriteLine(x.Bindings?.Count);

What do I need to change for this class to deserialize correctly?


Solution

  • The problem is that you cannot have an empty property name. The serializer assumes that the JSON you are deserializing is the type that you are providing.

    In your case, you can deserialize the JSON as a Dictionary<string, List<DriverUnitBinding>> directly though:

    string test = @"{""2534"":[{""t"":1711353044,""u"":10568}]}";
    var x = JsonSerializer.Deserialize<Dictionary<string, List<DriverUnitBinding>>>(test);
    Console.WriteLine(x?.Keys?.Count);
    

    enter image description here

    Another option, though maybe not the best route unless this makes sense for your data model, would be to have the GetDriverBindingsResponse simply inherit the Dictionary<string, List<DriverUnitBinding>> class as below.

    public class GetDriverBindingsResponse : Dictionary<string, List<DriverUnitBinding>>
    { }