I'm using the Newtonsoft JSON.NET package to deserialize my responses. This is a sample reponse from a call that pulls back available metrics from Omniture.
[
{"rsid":"somersid",
"site_title":"somesitetitle",
"available_metrics":[
{"metric_name":"averagepagedepth","display_name":"Average Page Depth"},
{"metric_name":"averagetimespentonpage","display_name":"Average Time Spent on Page"},
{"metric_name":"averagetimespentonsite","display_name":"Average Time Spent on Site"},
{"metric_name":"averagevisitdepth","display_name":"Average Visit Depth"},
{"metric_name":"customersdaily","display_name":"Daily Unique Customers"},
{"metric_name":"customersloyal","display_name":"Loyal Customers"},
{"metric_name":"customersmonthly","display_name":"Monthly Unique Customers"},
{"metric_name":"customersnew","display_name":"New Customers"},
{"metric_name":"customersquarterly","display_name":"Quarterly Unique Customers"}
]
}
]
For the classes I wanted to deserialize to I at first tried the classes that were generated by svcutil against their schema. It created the classes correctly and they appear to work when deserializing a simple object. But anything with a nested array (like above) was failing with the 'Cannot deserialize JSON array into type' error. Upon closer inspection, the svcutil generated classes were using arrays like this:
public partial class report_suite_metrics {
public string rsid { get; set;} ;
public string site_title { get; set;} ;
public metric[] available_metrics { get; set;} ;
}
public partial class metric {
public string metric_name {get; set;}
public string display_name {get; set;}
}
Maybe JSON.NET is trying to force that array to a generic List I thought. All the JSON.NET examples I saw used List to handle sub-arrays so I created new classes to test using the json2csharp utility (http://json2csharp.com/) and got this:
public class AvailableMetric {
public string metric_name { get; set; }
public string display_name { get; set; }
}
public class RootObject {
public string rsid { get; set; }
public string site_title { get; set; }
public List<AvailableMetric> available_metrics { get; set; }
}
which looks exactly in line with all the JSON.NET examples. But it throws the exact same error :( What gives? Anyone ran into this kind of issue? It seems like a very simple and common case so I was surprised it didn't just work as expected. Thanks
Both sets of types you've given work; the issue is the source data returned is an array of the core type, not a single instance. Note the square brackets in the JSON sample you've provided around the entire unit of data.
Here is a test console app that you can use to check the JSON you're seeing.
To use it, copy the JSON you have provided above into an arbitrary text file and open it from the app.
Note that deserializing as an array works fine, but single element (per your expectations) fails.
If you create a sample text file containing the same sample data but without the outer [ ] brackets, you'll see that the array deserialization fails and single elements work.
using System.Windows.Forms;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace RptSuiteMetricsTest1
{
class Program
{
public class report_suite_metrics
{
public string rsid { get; set; }
public string site_title { get; set; }
public metric[] available_metrics { get; set; }
}
public class metric
{
public string metric_name { get; set; }
public string display_name { get; set; }
}
public class AvailableMetric
{
public string metric_name { get; set; }
public string display_name { get; set; }
}
public class RootObject
{
public string rsid { get; set; }
public string site_title { get; set; }
public List<AvailableMetric> available_metrics { get; set; }
}
[STAThread]
static void Main(string[] args)
{
OpenFileDialog dlg = new OpenFileDialog();
DialogResult dr = dlg.ShowDialog();
if (dr != DialogResult.OK) { return; }
// NOTE: ...or replace this with a string containing the json data to test.
string jsonData = System.IO.File.ReadAllText(dlg.FileName);
Console.WriteLine("Deserialize as array");
try
{
report_suite_metrics[] dataset = JsonConvert.DeserializeObject<report_suite_metrics[]>(jsonData);
Console.WriteLine("{0} items found.", dataset.Length);
}
catch (Exception ex)
{
Console.WriteLine("Exception of type {0}", ex.GetType().Name);
}
Console.WriteLine("Deserialize as array, alternate type");
try
{
RootObject[] dataset = JsonConvert.DeserializeObject<RootObject[]>(jsonData);
Console.WriteLine("{0} items found.", dataset.Length);
}
catch (Exception ex)
{
Console.WriteLine("Exception of type {0}", ex.GetType().Name);
}
Console.WriteLine();
Console.WriteLine("Deserialize as single item");
try
{
report_suite_metrics dataset = JsonConvert.DeserializeObject<report_suite_metrics>(jsonData);
Console.WriteLine("rsid=\"{0}\"", dataset.rsid);
}
catch (Exception ex)
{
Console.WriteLine("Exception of type {0}", ex.GetType().Name);
}
Console.WriteLine("Deserialize as single item, alternate type");
try
{
RootObject dataset = JsonConvert.DeserializeObject<RootObject>(jsonData);
Console.WriteLine("rsid=\"{0}\"", dataset.rsid);
}
catch (Exception ex)
{
Console.WriteLine("Exception of type {0}", ex.GetType().Name);
}
Console.ReadKey();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With