I have a project where I need to read in a response from a Http server. The response is in Json. The object graph from that json deserializes to works for the most part, however the array at the lowest level fails, leaving a null.
I've created code below that can be pasted into a blank test project and run. The sole test fails and I can't work out why. The sample Json is the const string at the top.
I found that the JavaScriptSerializer
from System.Web.Extensions
does work (when I use List instead of arrays). However, the Json.Net equivalent does not work. There are two tests in the sample below, the Newtonsoft one fails, but why? What item of Newtonsoft documentation am I missing?
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using System.Collections.Generic;
/// <summary>
/// Unit Test project that also includes a reference to System.Web.Extensions.
/// Also includes Newtonsoft from NuGet.
/// The constant `_downloadRootObjectEg` holds the sample json.
/// </summary>
namespace Savaged
{
[TestClass]
public class DownloadDeserialisationTest
{
private const string _downloadRootObjectEg = "{ \"error\": \"\", \"success\": true, \"data\": [{ \"data\": [{ \"TextSearched\": \"New product\", \"TextFound\": \"New product\", \"data \": [{ \"x\": 0.585, \"y\": 0.21496437 }, { \"x\": 0.63666666, \"y\": 0.21496437 }, { \"x\": 0.6933333, \"y\": 0.23515439 } ], \"Page\": 16 }, { \"TextSearched\": \"Expiry\", \"TextFound\": \"Expiry\", \"data \": [{ \"x\": 0.6666667, \"y\": 0.16270784 }, { \"x\": 0.7133333, \"y\": 0.16270784 }, { \"x\": 0.7133333, \"y\": 0.18052256 }, { \"x\": 0.6666667, \"y\": 0.18052256 } ], \"Page\": 39 }, { \"TextSearched\": \"Expiry\", \"TextFound\": \"Expiry\", \"data \": [{ \"x\": 0.47833332, \"y\": 0.6686461 }, { \"x\": 0.52166665, \"y\": 0.6686461 }, { \"x\": 0.52166665, \"y\": 0.6864608 }, { \"x\": 0.47833332, \"y\": 0.6864608 } ], \"Page\": 43 } ], \"context\": { \"FileLocation\": \"Product-09-08-2007.pdf\", \"ID\": 1, \"Type\": \"product\" } }, { \"data\": [{ \"TextSearched\": \"New product\", \"TextFound\": \"New product\", \"data \": [{ \"x\": 0.585, \"y\": 0.21496437 }, { \"x\": 0.63666666, \"y\": 0.21496437 }, { \"x\": 0.6933333, \"y\": 0.23515439 }, { \"x\": 0.6433333, \"y\": 0.23515439 } ], \"Page\": 16 }, { \"TextSearched\": \"Expiry\", \"TextFound\": \"Expiry\", \"data \": [{ \"x\": 0.6666667, \"y\": 0.16270784 }, { \"x\": 0.7133333, \"y\": 0.16270784 }, { \"x\": 0.7133333, \"y\": 0.18052256 }, { \"x\": 0.6666667, \"y\": 0.18052256 } ], \"Page\": 39 } ], \"context\": { \"FileLocation\": \"Product-09-08-2007.pdf\", \"ID\": 1, \"Type\": \"product\" } } ], \"count\": 2 }";
[TestMethod]
public void DeserialiseTest()
{
var downloadRootObject =
JsonConvert.DeserializeObject<DownloadRootObject>(_downloadRootObjectEg);
Assert.IsNotNull(downloadRootObject.Data[0].Data[0].Data, "Why?");
}
[TestMethod]
public void JavaScriptSerializerTest()
{
var downloadRootObject = new System.Web.Script.Serialization.
JavaScriptSerializer().Deserialize<DownloadRootObject>(_downloadRootObjectEg);
Assert.IsNotNull(downloadRootObject.Data[0].Data[0].Data, "Why?");
}
}
#region Concrete implementation
public abstract class RootObjectBase
{
public string Error { get; set; }
public bool Success { get; set; }
}
public class DownloadRootObject : RootObjectBase
{
public DownloadRootObject()
{
Data = new List<WordSearch>();
}
[JsonConstructor]
public DownloadRootObject(List<WordSearch> data)
{
Data = data;
}
public List<WordSearch> Data { get; set; }
public int Count { get; set; }
}
public class WordSearch
{
public WordSearch()
{
Data = new List<Match>();
}
[JsonConstructor]
public WordSearch(Context context, List<Match> data)
{
Context = context;
Data = data;
}
public Context Context { get; set; }
public List<Match> Data { get; set; }
}
public class Context
{
public string FileLocation { get; set; }
public int ID { get; set; }
public string Type { get; set; }
}
public class Match
{
public Match()
{
Data = new List<PointF>();
}
[JsonConstructor]
public Match(List<PointF> data)
{
Data = data;
}
public int Page { get; set; }
// TODO switch this to System.Drawing.PointF
public List<PointF> Data { get; set; }
public string TextSearched { get; set; }
public string TextFound { get; set; }
}
public class PointF
{
public float X { get; set; }
public float Y { get; set; }
}
#endregion
}
All help is much appreciated!