49

When I can call the 3rd party api and get back a single class worth of data everything deserialises fine using this code

TheUser me = jsonSerializer.Deserialize(response, typeof(TheUser)) as TheUser

The problem comes when I try and deserialise JSON response content that is an array, such as

{
   "data": [
      {
         "name": "A Jones",
         "id": "500015763"
      },
      {
         "name": "B Smith",
         "id": "504986213"
      },
      {
         "name": "C Brown",
         "id": "509034361"
      }
   ]
}

I can only get the serialization to work if I use a custom wrapping class around the "data" member and that member needs to be of type List<object>. If it have them as type List<TheUser> I get ArgumentException from the JsonParser DesializeType method.

I originally tried to serialise without a wrapping type like this

List<TheUser> freinds = jsonSerializer.Deserialize(response, typeof(List<TheUser>)) as List<TheUser>;

but that just returns me an empty collection. Surely I must be able to have the array deserialize to a strongly typed list.

2
  • I have the same problem; if you deserialize response into a dynamic var instead of TheUser, then deserialized.data is available as a JArray -- any idea if you can convert that into List<something>? Commented Jan 25, 2013 at 15:43
  • Seems you should be able to (link). Commented Jan 25, 2013 at 16:15

8 Answers 8

34

Afer looking at the source, for WP7 Hammock doesn't actually use Json.Net for JSON parsing. Instead it uses it's own parser which doesn't cope with custom types very well.

If using Json.Net directly it is possible to deserialize to a strongly typed collection inside a wrapper object.

var response = @"
    {
        ""data"": [
            {
                ""name"": ""A Jones"",
                ""id"": ""500015763""
            },
            {
                ""name"": ""B Smith"",
                ""id"": ""504986213""
            },
            {
                ""name"": ""C Brown"",
                ""id"": ""509034361""
            }
        ]
    }
";

var des = (MyClass)Newtonsoft.Json.JsonConvert.DeserializeObject(response, typeof(MyClass));

return des.data.Count.ToString();

and with:

public class MyClass
{
    public List<User> data { get; set; }
}

public class User
{
    public string name { get; set; }
    public string id { get; set; }
}

Having to create the extra object with the data property is annoying but that's a consequence of the way the JSON formatted object is constructed.

Documentation: Serializing and Deserializing JSON

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

4 Comments

It is very easy to change DeSerializer in Hammock. Create a class that implements the Hammock.Serialization.IDeserializer interface. And then set that class as your Deserializer on the RestClient.
I agree that it's slightly annoying to add the extra object, hence my solution below. My approach also gets around you having to case like you are in the var des = (MyClass)... line. Not sure if either this or my solution is better than the other, just prefer not having to add the extra Data object and I generally try to avoid type casting.
How much does it make to first do a Json.Parse(jsonString) and then do a JsonConvert.DeserializeObject(parsedJson["data"]).ToString()) to finally obtain a list of User, performance and sanity wise? ;-)
I read this thread multiple times debugging the same problem. In my case I had to get the JSON in the right format for processing by the JSON.Net package. What I would offer to others facing a similar problem is use a TraceWriter as the error message help highlight a fault I did not see in the JSON file.
22

try

List<TheUser> friends = jsonSerializer.Deserialize<List<TheUser>>(response);

5 Comments

That doesn't compile, however isn't that just a differnt calling style that is going to result in the same underlying mthods being called in the same way? I do not see how that will get around my issue
This worked for me: List<TheUser> friends = JsonConvert.DeserializeObject<List<TheUser>>(response);
Thanks! This allowed me to deserialize an array of objects without wrapping them in a container object.
I like Homer's solution, I agree it's a bit cleaner than my solution as it obviates the need for having a parent class or having to implement an interface if you don't want to inherit from anything. -Eric
this one works for me with similar problem.
12

This worked for me for deserializing JSON into an array of objects:

List<TheUser> friends = JsonConvert.DeserializeObject<List<TheUser>>(response);

Comments

9

This solution seems to work for me and gets around having to code a bunch of classes with "Data" in them.

public interface IDataResponse<T> where T : class
{
    List<T> Data { get; set; }
}

public class DataResponse<T> : IDataResponse<T> where T : class
{
   [JsonProperty("data")]
   public List<T> Data { get; set; }
}

I should have included this to begin with, here is an example method using the above:

public List<TheUser> GetUser()
{
    var results = GetUserJson();
    var userList = JsonConvert.DeserializeObject<DataResponse<TheUser>>(results.ToString());

    return userList.Data.ToList();
} 

Comments

8

Json.NET - Documentation

http://james.newtonking.com/json/help/index.html?topic=html/SelectToken.htm

Interpretation for the author

var o = JObject.Parse(response);
var a = o.SelectToken("data").Select(jt => jt.ToObject<TheUser>()).ToList();

Comments

2

The JSON structure looks very familiar to a problem I described here - The answer there was to treat the JSON representation as a Dictionary<TKey, TValue>, even though there was only 1 entry.

If I am correct your key is of type string and the value of a List<T> where T represents the class TheUser.

If you want better serialisation performance check out using Silverlight Serializer, you'll need to build a WP7 version. Shameless plug - I wrote a blog post about this.

Comments

1

I like this approach, it is visual for me.

using (var webClient = new WebClient())
    {
          var response = webClient.DownloadString(url);
          JObject result = JObject.Parse(response);
          var users = result.SelectToken("data");   
          List<User> userList = JsonConvert.DeserializeObject<List<User>>(users.ToString());
    }

Comments

0

I suspect the problem is because the json represents an object with the list of users as a property. Try deserializing to something like:

public class UsersResponse
{
    public List<User> Data { get; set; }
}

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.