Friday, November 7, 2014

Dynamic JSON parsers in Microsoft.NET

We are aware of typical, static Json parsers, those can parse a json string to a predefined POCO C# object. This is practical for scenarios, where you have a pre-defined json schema, before you design your C# classes. Also your json object structure (json schema) should not change, if it does your code breaks, while parsing dynamic json string to your static C# object.

But mostly,

JSON is dynamic in nature

That's why most, No-SQL databases uses it or at least it's derivatives (like BSON by MongoDB). We've a situation here, where we've to parse such dynamic Json objects, that can change over time or changes based on other elements in the json.

For eg:

If you represent a 'system event' as Json, you've a different Json for a 'KeyEvent', when compared to a 'MouseEvent'.
See the example below.

"Key Event" example:
{      
eventType: "Key",
Args:
{
KeyCode: "35",
Special: "Shift"
}
}


"Mouse Event" example:
{
eventType: "Mouse",
Args:
{
Button: "Left",
Point:
{
X: "30",
Y: "45"
}
}
}



This is just a simple sample, that shows how dynamic Json, can change over time. Static Json parsers wont do well with such scenarios.

Our objective was to parse, such dynamic JSON, and put the values as key/value pairs to a RDBMS database.

Our research on Dynamic JSON parsers, provided two options



1. System.Json Namespace (From Microsoft)

2. Newtonsoft.Json Namespace (From Newtonsoft)


Both can be installed through Nuget in Visualstudio.

Install Newtonsoft JSON through package manager console
PM> Install-Package Newtonsoft.Json

Install System.Json through package manager console
PM> Install-Package System.Json -Version 4.0.20126.16343

System.Json Namespace



Microsoft way of doing it. But it has a major limitation. If you've multiple json objects, in the same string, it will not support parsing it, unless you split them by your own means.

The below shows a simple usage of System.Json, on parsing a json string.

string jsonStr = "{Name:'Test',Marks:['20','81']}";
JsonValue parsedJsonObject = JsonObject.Parse(jsonStr);
switch (parsedJsonObject.JsonType)
{
case JsonType.String:
case JsonType.Number:
case JsonType.Boolean:
//JSon properties, get the value by converting it to string
string value = Convert.ToString(parsedJsonObject);
break;
case JsonType.Array:
JsonArray jArray = parsedJsonObject as JsonArray;
for (int index = 0; index < jArray.Count; ++index)
{
JsonValue jArrayItem = jArray[index];
//Now recursively parse, each array item. i.e jArrayItem
}
break;
case JsonType.Object:
JsonObject jObject = parsedJsonObject as JsonObject;
foreach (string key in jObject.Keys)
{
JsonValue jSubObject = jObject[key];
//Now recursively parse, each usb item. i.e jSubObject
}
break;
}


Newtonsoft.Json Namespace



Excellent Json parser. It has a good performance over other parsers, when you've a bulk of Json objects to parse.

The below shows a simple usage of Newtonsoft.Json, on parsing a json string.

string jsonStr = "{Name:'Test',Marks:['20','81']}";
JToken parsedJsonObject = JToken.Parse(jsonStr);
switch (parsedJsonObject.Type)
{
case JTokenType.Raw:
case JTokenType.Boolean:
case JTokenType.Bytes:
case JTokenType.Date:
case JTokenType.Float:
case JTokenType.Guid:
case JTokenType.String:
case JTokenType.TimeSpan:
case JTokenType.Integer:
case JTokenType.Uri:
//JSon properties, get the value by converting it to string
string value = Convert.ToString(parsedJsonObject);
break;
case JTokenType.Array:
JArray jArray = parsedJsonObject as JArray;
for (int index = 0; index < jArray.Count; ++index)
{
JToken jArrayItem = jArray[index];
//Now recursively parse, each array item. i.e jArrayItem
}
break;
case JTokenType.Object:
JObject jObject = parsedJsonObject as JObject;
foreach (JProperty key in jObject.Properties())
{
JToken jSubObject = jObject[key.Name];
//Now recursively parse, each usb item. i.e jSubObject
}
break;
}


Also Newtonsoft, has one more advantage over System.Json, as


it can parse multiple json, included in the same string
For eg. It can parse a Json string something like this.
string jsonStr = "{hello:'there'} {goodbye:'you',Thanks:'you'}";

The below code snippet, shows how to parse a string that contains multiple 'Json' objects. It does read, the two different Json object, in two while loop iterations.

string jsonStr = "{hello:'there'} {goodbye:'you',Thanks:'you'}";
using (var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonStr)))
{
var serializer = new JsonSerializer();
using (var reader = new StreamReader(stream))
using (var jsonReader = new JsonTextReader(reader))
{
//Setting, to read multiple json, if it exists
jsonReader.SupportMultipleContent = true;
while (jsonReader.Read())
{
var obj= serializer.Deserialize(jsonReader);
}
}
}


Conclusion




So in essence, 'System.Json' is an obvious option, for those who always wants packages provided by Microsoft. For client environments, where security is a major concern, this will be the most viable option.

But if you need more advanced options, like 'parsing a json string that contains multiple json objects', you can rely on 'Newtonsoft.Json' namespace.

If you've aware about, such products, mention them in comments.


No comments:

Post a Comment