views:

3419

answers:

2

I've got the following piece of JSON:

[{
    "name": "numToRetrieve",
    "value": "3",
    "label": "Number of items to retrieve:",
    "items": {
        "1": "1",
        "3": "3",
        "5": "5"
    },
    "rules": {
        "range": "1-2"
    }
},
{
    "name": "showFoo",
    "value": "on",
    "label": "Show foo?"
},
{
    "name": "title",
    "value": "Foo",
    "label": "Foo:"
}]

All in one line version (suitable for a string literal):

[{\"name\":\"numToRetrieve\",\"value\":\"3\",\"label\":\"Number of items to retrieve:\",\"items\":{\"1\":\"1\",\"3\":\"3\",\"5\":\"5\"},\"rules\":{\"range\":\"1-2\"}},{\"name\":\"showFoo\",\"value\":\"on\",\"label\":\"Show foo?\"},{\"name\":\"title\",\"value\":\"Foo\",\"label\":\"Foo:\"}]

In the above example, name, value, and label are required but items and rules are optional.

Here's the class I'm trying to deserialize into:

using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace foofoo
{
    [DataContract]
    public sealed class FooDef
    {
     [DataMember(Name = "name", IsRequired = true)]
     public string Name { get; set; }

     [DataMember(Name = "value", IsRequired = true)]
     public string Value { get; set; }

     [DataMember(Name = "label", IsRequired = true)]
     public string Label { get; set; }

     [DataMember(Name = "items", IsRequired = false)]
     public Dictionary<string, string> Items { get; set; }

     [DataMember(Name = "rules", IsRequired = false)]
     public Dictionary<string, string> Rules { get; set; }
    }
}

Here's the code I use to deserialize:

var json = new DataContractJsonSerializer(typeof(List<FooDef>));
var bar = "[{\"name\":\"numToRetrieve\",\"value\":\"3\",\"label\":\"Number of items to retrieve:\",\"items\":{\"1\":\"1\",\"3\":\"3\",\"5\":\"5\"},\"rules\":{\"range\":\"1-2\"}},{\"name\":\"showFoo\",\"value\":\"on\",\"label\":\"Show foo?\"},{\"name\":\"title\",\"value\":\"Foo\",\"label\":\"Foo:\"}]";
var stream = new MemoryStream(Encoding.UTF8.GetBytes(bar));
var foo = json.ReadObject(stream);
stream.Close();

Everything goes reasonably well except that items and rules are empty for the first FooDef pass. I have tried everything under the sun to try and get them populated: custom classes, NameValueCollection, KeyValuePair<string, string>, List of both of the latter, and every other collection that seemed to apply. [EDIT: I forgot to try Hashtable, which seemed like an obvious candidate. Didn't work.]

The problem, as I see it, is that the key piece under items and rules is open-ended. That is, it's not always going to be called range or 3. Any advice or ideas?

+3  A: 

IMHO there is no way to serialize the JSON string you provided into a .NET class using DataContractJsonSerializer.

The problem comes from the way DataContractJsonSerializer serializes dictionaries. You could use an alternative serializer such as Json.NET (which I strongly recommend) or JavaScriptSerializer (I think it was deprecated in favor of DataContractJsonSerializer but it will work for your scenario).

You can also read these rants.

Darin Dimitrov
That's kind of what I feared. I was avoiding switching over to JavaScriptSerializer because of the deprecation, but I'm glad to hear that it was undeprecated in 3.5 SP1. I'll try it using that class.
bbrown
I tried it with JavaScriptSerializer and it worked perfectly. I ended up using Dictionary<string, string> but Hashtable worked also.
bbrown
A: 

http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/071f73bb-e141-4a68-ae61-05635382934f

Check this article out - it solved my problem almost perfectly. I had to change their object[] Type to a string, but i'm only using strings:string type Key/Value pairs, so no problems there.

Sean Kelly