2

I'm having trouble deserializing a JSON array of mixed types using the DataContractJsonSerializer class. I've spent a bunch of time looking for a solution to no avail, so I thought I'd go ahead and ask here.

Basically, I am getting a JSON string like the one below. I'd like to get the array to deserialize into an List where position 0 has an Int32, position 1 has a String, and position 2 has an instance of my custom class.

[
   2,
   "Mr. Smith",
   {
      "num":169,
      "name":"main street",
      "state":66
   }
]

If I just create a serialize like so:

DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<object>))

I actually get an Int32 at position 0 and a String at position 1. However at position 2 I just get a null object.

Does anyone know if what I am trying to do is even possible? I have no control over the structure of the JSON that I'm consuming. I'd like to accomplish this without using third party assemblies if possible.

dbc
  • 104,963
  • 20
  • 228
  • 340
Mike
  • 21
  • 1
  • 2

2 Answers2

2

You have to make a class that reproduces the json structure like this:

[DataContract]
public class MyClass {
    [DataMember]
    public int IntMember { get; set; }
    [DataMember]
    public string StringMember { get; set; }
    [DataMember]
    public MyType[] AllTypes { get; set;}
}

[DataContract]
public class MyType {
    [DataMember]
    public int num { get; set; }
    [DataMember]
    public string name { get; set; }
    [DataMember]
    public int state { get; set;}
}

Decorate the class and its properties with the "DataContract" and "DataMember" attributes. Then in your deserializing code use the class you have created as in the following example

var serializer = new DataContractJsonSerializer(typeof(MyClass));
System.IO.StringReader reader = new System.IO.StringReader(jsonData);
System.IO.MemoryStream ms = new System.IO.MemoryStream(Encoding.Default.GetBytes(jsonData));
return serializer.ReadObject(ms) as MyClass;
Lorenzo
  • 29,081
  • 49
  • 125
  • 222
  • That is what thought initially as well. The problem is that an array such as this wont deserialize to a single class. The serializer is forcing this to deserialize as an array. When I tried this I got the error "Expecting state 'Element'.. Encountered 'Text' with name '', namespace ''." – Mike Oct 11 '10 at 00:55
  • Please have a look to my last edit. I did forgot that it was an array of elements... – Lorenzo Oct 11 '10 at 00:58
  • Lorenzo, thanks for code sample. This dosen't seem to work either. This produces an instance of MyClass with the int member = 0 and null for the other two members. Something is still missing... – Mike Oct 11 '10 at 03:12
  • @Mike: Please have a look here: `http://www.codeproject.com/KB/aspnet/AspNetMVCandJqGrid.aspx`. Besides the argument of the article, there's a bit of code in the GridModelBinder class that does something exactly as per your sample. And it works believe me. :) – Lorenzo Oct 11 '10 at 07:53
1

Mike,

The problem is that during deserialization, the JSON deserializer does not know what type to deserialize the element at position 2 to.

You need to provide a "__type" hint. You can get the __type hint for thie particular type by actually serializing it out to JSON in a polymorphic situation, and seeing what type hint gets emitted.

For more info, see http://msdn.microsoft.com/en-us/library/bb412170.aspx. Pay particular attention to the sections "Collections Assigned to Object" and "Preserving Type Information"

krisragh MSFT
  • 1,908
  • 1
  • 13
  • 22