32

Given the following json:

[ {"id":"123", ... "data":[{"key1":"val1"}, {"key2":"val2"}], ...}, ... ]

that is part of a bigger tree, how can I deserialize the "data" property into:

List<MyCustomClass> Data { get; set; }

or

List<KeyValuePair> Data { get; set; }

or

Dictionary<string, string> Data { get; set; }

using Json.NET? Either version will do (I prefer List of MyCustomClass though). I already have a class that contains other properties, like this:

public class SomeData
{
   [JsonProperty("_id")]
   public string Id { get; set; }
   ...
   public List<MyCustomClass> Data { get; set; }
}

where "MyCustomClass" would include just two properties (Key and Value). I noticed there is a KeyValuePairConverter class that sounds like it would do what I need, but I wasn't able to find an example on how to use it. Thanks.

1
  • i used this wizard as well json2csharp.com to generate class for deserialized Commented Jul 31, 2018 at 23:40

5 Answers 5

37

The simplest way is deserialize array of key-value pairs to IDictionary<string, string>:


public class SomeData
{
    public string Id { get; set; }

    public IEnumerable<IDictionary<string, string>> Data { get; set; }
}

private static void Main(string[] args)
{
    var json = "{ \"id\": \"123\", \"data\": [ { \"key1\": \"val1\" }, { \"key2\" : \"val2\" } ] }";

    var obj = JsonConvert.DeserializeObject<SomeData>(json);
}

But if you need deserialize that to your own class, it can be looks like that:


public class SomeData2
{
    public string Id { get; set; }

    public List<SomeDataPair> Data { get; set; }
}

public class SomeDataPair
{
    public string Key { get; set; }

    public string Value { get; set; }
}

private static void Main(string[] args)
{
    var json = "{ \"id\": \"123\", \"data\": [ { \"key1\": \"val1\" }, { \"key2\" : \"val2\" } ] }";

    var rawObj = JObject.Parse(json);

    var obj2 = new SomeData2
    {
        Id = (string)rawObj["id"],
        Data = new List<SomeDataPair>()
    };

    foreach (var item in rawObj["data"])
    {
        foreach (var prop in item)
        {
            var property = prop as JProperty;

            if (property != null)
            {
                obj2.Data.Add(new SomeDataPair() { Key = property.Name, Value = property.Value.ToString() });
            }

        }
    }
}

See that I khow that Value is string and i call ToString() method, there can be another complex class.

Sign up to request clarification or add additional context in comments.

4 Comments

The list of dictionaries works; thanks for that. Since the change I'm trying to make is part of a bigger library I'm trying to avoid having to write custom object initialization. I'm looking into writing a custom converter for my class (SomeData2 in your example). If I can't get it to work then I'll use your List of Dictionary method. Thanks.
Thanks alot for this answer. I was having same kind of json with array with key value. I just used public IEnumerable<IDictionary<string, string>> Data { get; set; } for that field and worked like charm.. my whole json was parsed fine!..
Note that this will not conserve the order of the original JSON - since a Dictionary will be sorted by the Key
Granted, that it doesn't populate one Dictionary<string, string> but I think that would be more logical. Seems silly to need an enumerable (or array) of IDictionary when the idea of a dictionary to begin with is to be a keyed collection of values.
4

Thanks @Boo for your answer but in my case I needed to take some small adjustements. This is how my JSON looks like:

{
    "rates": {
        "CAD": 1.5649,
        "CZK": 26.118,
        ...
    },
    "base": "EUR",
    "date": "2020-08-16"
}

And my DTO looks like the following:

public IDictionary<string, decimal> Rates { get; set; }
public string Base { get; set; }
public DateTime Date { get; set; }

So the only adjustement was to remove the IEnumerable around the IDictionary.

Comments

2

I ended up doing this:

[JsonConverter(typeof(MyCustomClassConverter))]
public class MyCustomClass
{
  internal class MyCustomClassConverter : JsonConverter
  {
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
      throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
      JObject jObject = JObject.Load(reader);

      foreach (var prop in jObject)
      {
        return new MyCustomClass { Key = prop.Key, Value = prop.Value.ToString() };
      }

      return null;
    }

    public override bool CanConvert(Type objectType)
    {
      return typeof(MyCustomClass).IsAssignableFrom(objectType);
    }
  }

  public string Key { get; set; }
  public string Value { get; set; }
}

Comments

0
public class Datum
{
    public string key1 { get; set; }
    public string key2 { get; set; }
}

public class RootObject
{
    public string id { get; set; }
    public List<Datum> data { get; set; }
}

i used this wizard as well json2csharp.com to generate class for deserialized

for using that

using RestSharp;
using Newtonsoft.Json;

IRestResponse restSharp= callRestGetMethodby_restSharp(api_server_url);
string jsonString= restSharp.Content;

RootObject rootObj= JsonConvert.DeserializeObject<RootObject>(jsonString);
return Json(rootObj);

if you call rest by restsharp

    public IRestResponse callRestGetMethodby_restSharp(string API_URL)
    {
        var client = new RestSharp.RestClient(API_URL);
        var request = new RestRequest(Method.GET);
        request.AddHeader("Content-Type", "application/json");
        request.AddHeader("cache-control", "no-cache");
        IRestResponse response = client.Execute(request);
        return response;
    }

also you can get this 6 line of restsharp from getpostman.com tools

1 Comment

json2csharp.com was a great suggestion! thanks
0

You can use public IEnumerable<IDictionary<string, string>> Data as the most answers are recommending, but it is not the best idea, since it creates a new dictionary for each array key value item. I recommend to use List<KeyValuePair<string, string>> instead ( or you can create a custom class as well instead of using KeyValuePair )

var json = "[{ \"id\": \"123\", \"data\": [ { \"key1\": \"val1\" }, { \"key2\" : \"val2\" } ] }]";

List<SomeData> listSomeData = JsonConvert.DeserializeObject<List<SomeData>>(json);

public class SomeData
{
    [JsonProperty("id")]
    public string Id { get; set; }

    public List<KeyValuePair<string, string>> Data { get; set; }

    [JsonConstructor]
    public SomeData(JArray data)
    {
        Data = data.Select(d => new KeyValuePair<string, string>(
        ((JObject)d).Properties().First().Name,
        ((JObject)d).Properties().First().Value.ToString()))
        .ToList();
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.