0

How can I parse the JSON object below using DataContractJsonSerializer in C#?

I will need to define a class to hold the below JSON data, which includes an array of arrays of primitives of mixed types (string and integer):

Body:
    {
      "status": "failure",
      "staticdata": [
        [
          "2013-06-01",
          123
        ],
        [
          "2013-06-02",
          234
        ],
        [
          "2013-06-03",
          345
        ],    
        ...
      ]
    }

I tried the below answer and tried to read through DataContractJsonSerializer,

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(RootObject));

object objResponse = jsonSerializer.ReadObject(response);

RootObject jsonResponse = objResponse as RootOject;

foreach (object[] sd in jsonResponse.staticdata)
{
    foreach (object o in sd)
    {
        //Value val = v as Value;
        Value val = (Value)Convert.ChangeType(o, typeof(Value));
            log.Info("date: " + val.date);
            log.Info("crashCount: " + val.longValue);
   }
} 

but in converttype from object to Value is crashing, am I missing something here.

Value is below class:

[DataContract]
public class Value
{
    [DataMember(Name = "date")]
    public string date { get; set; }

    [DataMember(Name = "longValue")]
    public long longValue{ get; set; }
}

modified code read Values (IgnoreDataMember Values), and then could able to read as below: is this the right approach?

object objResponse = jsonSerializer.ReadObject(response);

RootObject jsonResponse = objResponse as RootOject;

foreach (Value in jsonResponse.Values)
{
            log.Info("date: " + val.date);
            log.Info("longValue: " + val.longValue);
} 
dbc
  • 104,963
  • 20
  • 228
  • 340
user1174114
  • 178
  • 1
  • 19
  • See http://stackoverflow.com/questions/9034220/parse-an-array-as-a-json-string-using-datacontractjsonserializer-wp7 – Stuart Feb 22 '17 at 14:18
  • http://stackoverflow.com/questions/27174549/how-to-use-datacontractjsonserializer-to-parse-a-nested-json-object http://stackoverflow.com/questions/9034220/parse-an-array-as-a-json-string-using-datacontractjsonserializer-wp7 and so on... 3seconds of googling – Tomasz Juszczak Feb 22 '17 at 14:18
  • Why dont you use Json.Net? It is much more easier – NicoRiff Feb 22 '17 at 14:18
  • 2
    Possible duplicate of [parse an array as a Json string using DataContractJsonSerializer WP7](http://stackoverflow.com/questions/9034220/parse-an-array-as-a-json-string-using-datacontractjsonserializer-wp7) – Tomasz Juszczak Feb 22 '17 at 14:19
  • ok, but here [ "2013-06-01", 123 ], doesn't have any name.. – user1174114 Feb 22 '17 at 14:23

1 Answers1

3

If you just want to deserialize your JSON, you can use a code-generation tool like http://json2csharp.com/ or Paste JSON As Classes and get the following data model, which works perfectly well with DataContractJsonSerializer:

public class RootObject
{
    public string status { get; set; }
    public List<List<object>> staticdata { get; set; }
}

object works because DataContractJsonSerializer automatically recognizes and serializes known primitive types such as string and int.

But what you may want is to deserialize your "staticdata" array to a list of classes such as this:

public class Value
{
    public string Date { get; set; }
    public int IntValue { get; set; }
}

If so, you can make use of a surrogate property in the RootObject type to do the conversion:

[DataContract]
public class RootObject
{
    [DataMember]
    public string status { get; set; }

    [DataMember]
    object[][] staticdata
    {
        get
        {
            if (Values == null)
                return null;
            return Values.Select(v => new object[] { v.Date, v.IntValue }).ToArray();
        }
        set
        {
            if (value == null)
                return;
            Values = value.Select(a => new Value 
                { 
                    Date = a.Length < 1 ? null : (string)Convert.ChangeType(a[0], typeof(string), CultureInfo.InvariantCulture),
                    IntValue = a.Length < 2 ? 0 : (int)Convert.ChangeType(a[1], typeof(int), CultureInfo.InvariantCulture) 
                }
                ).ToList();
        }
    }

    [IgnoreDataMember]
    public List<Value> Values { get; set; }
}

Update

In your updated question you asked, but in converttype from object to Value is crashing, am I missing something here?

Your problem is that you are trying to use Convert.ChangeType() to convert an object to a Value, but this method is only for primitive data types that can be converted from and to strings. From the docs:

ChangeType is a general-purpose conversion method that converts the object specified by value to conversionType. The value parameter can be an object of any type, and conversionType can also be a Type object that represents any base or custom type. For the conversion to succeed, value must implement the IConvertible interface, because the method simply wraps a call to an appropriate IConvertible method.

As your Value type does not implement this interface, conversion fails.

Instead, you should use Convert.ChangeType on the individual entries in the nested arrays. Given your RootObject looks like:

public class RootObject
{
    public string status { get; set; }
    public object [][] staticdata { get; set; }
}

You should do:

using System.Linq;

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(RootObject));
var jsonResponse = (RootObject)jsonSerializer.ReadObject(response);

var query = jsonResponse.staticdata
    // For each object [] array in the outer array
    .Select(a => new Value
        {
             // Convert the inner array to a Value, using the first element for the date and the second element for the longValueand the second element for the longValue
            date = a.Length < 1 ? null : (string)Convert.ChangeType(a[0], typeof(string), CultureInfo.InvariantCulture),
            longValue = a.Length < 2 ? 0 : (long)Convert.ChangeType(a[1], typeof(long), CultureInfo.InvariantCulture)
        });

foreach (var val in query)
{
    log.Info("date: " + val.date);
    log.Info("crashCount: " + val.longValue);
}
dbc
  • 104,963
  • 20
  • 228
  • 340