skip to Main Content

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.

5

Answers


  1. The default serialization of type KeyValuePair<string, Subscription> looks like this:

    {
        "key":
          "305FDF11-25E7-43DE-B09D-DFFC17C79599",
        "value":{
         "hasRead":true,
         "timeStamp":"XXX"
        }
    }
    

    To change this behavior you need to write your own converter derrived from JsonConverter class.
    Also note that true value should be without quotes.

    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
  3. You have two issues.

    1)

          string json = @"
          {
            ""305FDF11-25E7-43DE-B09D-DFFC17C79599"": {
              ""hasRead"": ""true"",
              ""Timestamp"": ""XXX""
            }
          }
        ";
    

    true is surrounded by quotes. By default that will not deserialise to a boolean but a string. You can change the type of HasRead in the Subscription class to fix the issue. If you want a boolean property then you could add something like:

    public bool HasReadBool => bool.Parse(HasRead);
    

    You cannot deserialise directly to a KeyValuePair as that has named Key and Value properties. Instead you can deserialise to a Dictionary:

     var deser = JsonSerializer.Deserialize<Dictionary<string, Subscription>>(json,
            new JsonSerializerOptions(JsonSerializerDefaults.Web));
    

    If you want to get a KeyValuePair you can do this: var kvp = deser.First()

    Login or Signup to reply.
  4. 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"",
                  ""Timestamp"": ""XXX""
                }
              }
            ";
    
            // deserialize the JSON string into a dictionary
            var dict = JsonSerializer.Deserialize<Dictionary<string, Subscription>>(json,
                new JsonSerializerOptions(JsonSerializerDefaults.Web));
    
            // iterate over the dictionary and print each key-value pair
            foreach (var kvp in dict)
            {
                Console.WriteLine($"Key: {kvp.Key}");
                Console.WriteLine($"HasRead: {kvp.Value.HasRead}");
                Console.WriteLine($"TimeStamp: {kvp.Value.TimeStamp}");
            }
        }
    }
    
    Login or Signup to reply.
  5. We can use type Dictionary<String,Subscription> to achieve it.

    using System.Text.Json;
    
    class JsonTest
    {
        public class Subscription
        {
            public bool HasRead { get; set; } = true;
            public string TimeStamp { get; set; } = "";
        }
        public static void Main()
        {
            string json = @"
                 {
                     ""305FDF11-25E7-43DE-B09D-DFFC17C79599"": {
                          ""hasRead"": ""true"",
                          ""TimeStamp"": ""XXX""
                      }
                 }
                 ";
    
            var deser = JsonSerializer.Deserialize<Dictionary<string, Subscription>>(json);
            foreach(var key in deser.Keys)
            {
                Subscription subscription = deser[key];
                Console.WriteLine($"Key:{key} HasRead:{subscription.HasRead} TimeStamp:{subscription.TimeStamp}");
            }
        }
    }
    

    I tried to print all values.
    Output is :-

    Key:305FDF11-25E7-43DE-B09D-DFFC17C79599 HasRead:True TimeStamp:XXX
    

    Note :- We should try to match case in json and class properties. Else, We will get null/default values. I have modified Timestamp to TimeStamp in JSON string.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search