3

How do I deserialize the following JSON with Web API (JSON.Net)?:

{
    "action": "edit",
    "table": "MainView",
    "id": "row_1377",
    "_group_id": "999",
    "data": {
        "ROTATION": "1", // This name/val can change
        "EQUIPMENT": [{
            "id": "6"
        },
        {
            "id": "8"
        }],
        "NOTES": ""
    }
}

The values in data represent columns and can change, so I can't make a set-in-stone object with e.g. a string named "NOTES" as in json.net deserialize string to nested class.

Notice EQUIPMENT contains multiple values. When it was previously just a "string:string" like NOTES, this JSON deserialized data into a Dictionary<string, string>, but now I need it to behave like its own dictionary. My last attempt was to deserialize into the following type:

public class EditorSubmissionJoined
{
    public string _group_id { get; set; }
    public string action { get; set; }
    public string table { get; set; }
    public string id { get; set; }
    // "public" added below due to mistake noticed by Maggie Ying
    public Dictionary<string, object> data { get; set; } // Trouble
}

I was hoping that the object could contain anything in data whether a KeyValuePair (like NOTES) or a dictionary (like EQUIPMENT).

I've also tried Dictionary<string, ICollection<Object>>, Object, and even ICollection<Dictionary<string, Object>>.

The problem is that my controller always gets EditorSubmissionJoined with nothing but null values:

public void Put(EditorSubmissionJoined ajaxSubmission) {
    // ajaxSubmission has only NULL values
}
Community
  • 1
  • 1
Charles Burns
  • 10,310
  • 7
  • 64
  • 81
  • 2
    You should be able to deserialze to dynamic: http://stackoverflow.com/questions/4535840/deserialize-json-object-into-dynamic-object-using-json-net – Preston Guillot Oct 10 '12 at 23:08

2 Answers2

2

Try setting your 'data' property to public and your JSON should be able to model bind correctly.

Maggie Ying
  • 10,095
  • 2
  • 33
  • 36
  • Very observant. Unfortunately only the code I posted with the `Dictionary` was private (oops) because my actual code uses a base class which I simplified, and messed up, for my SO post. – Charles Burns Oct 11 '12 at 14:19
1

There's a few ways you can do it. One way is to simply use a JObject and access the fields by name e.g. : jsonObject["data"]["ROTATION"]. You can "deserialize" that with JObject.Parse and just "parse" the JSON text into a JObject.

Alternatively you can write your own JsonConverter and tell JSON.net to use that converter when deserializing a specific type (e.g. JsonConverterAttribute). This requires parsing parts of the JSON text manually, in the ReadJson override, and really depends on what data you expect.

You can also use the dynamic approach that Preston commented on.

Which approach you pick depends on how strongly-typed you want things to be.

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
  • It's too bad JSON.net does not yet support the more strongly typed approach without having to write a converter, but I'll have to work within the system. Thanks. – Charles Burns Oct 11 '12 at 17:03
  • Well, the problem is that "data" varies depending on some state. I suppose you could define a "data" class that encompasses all the possible name/value pairs that `data` could ever have. But then you have a fairly unwieldy class and it becomes hard to know what fields are valid in what context. There's also the problem with values that change type based on context. (e.g. if VALUE is a string in one context and a date/time in another)... – Peter Ritchie Oct 11 '12 at 17:12
  • It does seem though that, in this example, `data` could be serialized to an `Object` which contains `KeyValuePair`s and a collection of dictionaries. True, for a truly dynamic object it would be inconvenient to not know the results ahead of time, but in this and most cases I believe the problem isn't bad: `For each Object in data {If it's a dictionary do X else if it's a KeyValuePair do Y.}` I'm sure the JSON.Net author put a lot of thought into this and has his reasons. – Charles Burns Oct 11 '12 at 17:19
  • @CharlesBurns yep, a `JObject` is basically a key/value pair container. The value is a JToken which is often a JValue object... – Peter Ritchie Oct 11 '12 at 17:43