4

Below is an example of the JSON format I'm receiving from an external API:

"object": {
  "property_1": {
    "values": {
      "value": 1,
      "displayValue": "1"
    }
  },
  "property_5": {
    "values": {
      "value": 3,
      "displayValue": "3"
    }
  },
  "property_8": {
    "values": {
      "value": 1,
      "displayValue": "1"
    }
  },
  "property_14": {
    "values": {
      "value": 392,
      "displayValue": "392.0"
    }
  },
  "property_17": {
    "values": {
      "value": 14,
      "displayValue": "14"
    }
  }
}

There are somewhere around 100 different property types that can be sent, but they all follow the same structure. The only distinction is the name of the property ("property_1", "property_5", etc). Rather than attempting to write a class with a long list of properties that are not always used, I think it'd be much more useful to parse this into a list of objects, using the property name in the resulting class like so:

public class Property
{
    public string Name { get; set; }
    public PropertyValues Values { get; set; }
}

public class PropertyValues
{
    public double Value { get; set; }
    public string DisplayValue { get; set; }
}

In this case, the property name ("property_1", "property_5", etc) would be assigned to the Name field of the Property object.

How can this be accomplished using Json.NET?

2 Answers 2

9
var result  = JsonConvert.DeserializeObject<Root>(json);

You model is below


public class Root
{
    public Dictionary<string, ValueWrapper> Object { get; set; }
}
public class ValueWrapper
{
    public PropertyValues Values { get; set; }
}

public class PropertyValues
{
    public int Value { get; set; }
    public string DisplayValue { get; set; }
}

BTW: Json.Net can handle dynamic more easily than proposed by @MatíasFidemraizer...

var val = ((dynamic)JsonConvert.DeserializeObject(jsonstring))
          [email protected]_14.values.value;

var val = ((dynamic)JsonConvert.DeserializeObject(jsonstring))
          .@object["property_14"].values.value;

But this approach would require you to know property_14 will be returned by your server beforehand...

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

4 Comments

It's terrible to say some other contributor that has repeated your answer when a part of the whole answer is the exact approach provided by me. In other Q&As other answerers are more mature than you and usually use links to the other answerer saying "like has already said @matias-fidemraizer on his answer, you can use the dynamic approach too"... Actually, I care about contributing with good answers and suggestions that I really feel that are useful for the OP. In my case, I'm not a fame hunter, I just answer my point of view, I don't care if you get 100 more upvotes and I even get downvotes.
Well, I care if I get downvotes to IMPROVE my answer.
Thanks for the mention. IMHO and based on my experience, it's better to go with ExpandoObject than JObject on this cases, because remember that JSON.NET provide implicit conversions to turn a JSON value into a simple type like string , bool, int, and this can end up in some overload resolution issues... BTW, in other cases deserializing to dynamic as JObject is enough...
Also now I understand your and @EZI concerns when you edited again and you show how you access "property_14". I see that this issues are gone when you use ExpandoObject. Now the OP has 2 or 3 approaches to solve the same issue. Now I need to go to bed! Good night.
1

There's even another approach: you can use expando objects:

dynamic response = JsonConvert.DeserializeObject<ExpandoObject>("JSON TEXT", new ExpandoObjectConverter());

And you can access properties using dynamic typing:

long someValue = [email protected]_1.values.value;

Also, since ExpandoObject implements IDictionary<string, object>, you can use it like a dictionary and check if a property exists:

if(((IDictionary<string, object>)response.@object).ContainsKey("property_1"))
{

}

It seems like you're going to save a lot of time going this way!

Answering hate on this answer

It seems like the most hate on my answer is focused on this @EZI comment:

And suppose you don't know property_14 before deserializing the json..

And the other answerer @L.B argues this on his own answer:

But this approach would require you to know property_14 will be returned by your server beforehand...

In my case, I find that this concern is already addressed in my answer when I mention that ExpandoObject implements IDictionary<string, object>. Perhaps you don't know that property_14 will be part of deserialized object graph. No problem:

if(((IDictionary<string, object>)response.@object).ContainsKey("property_14"))
{
    // You've already addressed the issue, because you won't get a 
    // run-time exception since you'll access such property if it's already
    // in the returned response...
    object property_14 = [email protected]_14;
}

15 Comments

So generic that, can be posted to any json related question.... And suppose you don't know property_14 before deserializing the json....
It doesn't even work... string property14Value = response.property14Value; throws exception....
@EZI Sorry but you know why it throws an exception, because it should be response.object.property14value. I'm going to fix this.
@EZI Fixed, BTW I feel that I got both a lot of love and hate (3 downvotes) while the approach works flawlessly in a lot of scenarios. And, IMHO, OP can take advantage of my approach. The fact that I gave a wrong dynamic property access is just a human error, while it doesn't defeat the purpose of my answer: I'm giving OP a good hint.
BTW: I'd also like to know who voted +1 or -1 before/after testing the code in this answer....
|

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.