Search code examples
c#jsondeserialization

C# deserialize KeyValuePair from JSON


This is the absolute simplest version of this question (a subset of it).

using System;
using System.Collections.Generic;
using System.Text.Json;


public class Program
{
    public class Subscription
    {
        public bool HasRead { get; set; } = true;
        public string TimeStamp { get; set; } = "";
    }



    public static void Main()
    {
        // this input format is a requirement. It cannot be changed.
        string json = @"
          {
            ""305FDF11-25E7-43DE-B09D-DFFC17C79599"": {
              ""hasRead"": true, // EDIT: Removed the double quotes around the boolean. That was not the core issue.
              ""Timestamp"": ""XXX""
            }
          }
        ";

        // I'm trying to find the correct deserialization type in C#
        var deser = JsonSerializer.Deserialize<KeyValuePair<string, Subscription>>(json,
            new JsonSerializerOptions(JsonSerializerDefaults.Web));

        // System.Text.Json.JsonException: 
        //'The JSON value could not be converted to 
        //System.Collections.Generic.KeyValuePair
    }
}

I can't understand why that can't be deserialized.

Note: I'm obsessing over the KeyValuePair type but maybe it has to do with the casing of the fields or something else obvious.

Other note : It still fails when I change KeyValuePair<string, Subscription> to KeyValuePair<string, object> to make it more permissive.


Solution

  • First of all, your JSON does not conform to default serialization of KeyValuePair<string, Subscription>, I'd recommend switching the type to Dictionary<string, Subscription>. As well, default JSON deserializer is unable to deserialize your JSON. I'd recommend using Newtonsoft.Json

    using Newtonsoft.Json;
    
    string json = @"
              {
                ""305FDF11-25E7-43DE-B09D-DFFC17C79599"": {
                  ""hasRead"": ""true"",
                  ""Timestamp"": ""XXX""
                }
              }
            ";
    
    var deserialized = JsonConvert.DeserializeObject<Dictionary<string, Subscription>>(json);
    var subscription = deserialized["305FDF11-25E7-43DE-B09D-DFFC17C79599"];
    Console.WriteLine($"Subscription timestamp is {subscription.TimeStamp}");
    

    Like this you'd get output of Subscription timestamp is XXX.