LINQ to JSON – Checking for an Object or Array
I was writing an event handler for my book that consumes a stream of JSON from a RESTful service. The handler is called when one of several asynchronous events is invoked. All of these events request a steam of either 1 or more products to be returned as JSON. So I wanted this handler to be able to consume the JSON whether it was a single product or an array of products.
The JSON is not wrapped, so a single object will not convert to a JsonArray. What I really wanted was to avoid writing the same LINQ to JSON query just to change out if it was looking for an object or an array. The way I handled this is to parse the raw JSON (a string variable) into a JsonArray object. If the JSON is a single object then when it is cast to a JsonArray it will be null. So at that point I know if it is an array of products or a single product.
Then, in the IF statement if it is a single object I parse the JSON into a JsonObject, create an instance of a JsonArray and add the JsonObject to the JsonArray. If the JSON data can be parsed into a JsonArray, the ELSE section parses it into a JsonArray. So in the end I have a JsonArray of either 1 or more objects. Why is this important? Because the query can now be written to find a list of products without having to handle wether it comes form a JsonObject or against a JsonArray.
C#
private void ParseProducts_AsJson(object sender, DownloadStringCompletedEventArgs e)
{
string raw = e.Result;
JsonArray json;
if (JsonArray.Parse(raw) as JsonArray == null)
json = new JsonArray {JsonObject.Parse(raw) as JsonObject};
else
json = JsonArray.Parse(raw) as JsonArray;
var query = from product in json
select new Product
{
ProductId = (int)product["ProductId"],
ProductName = (string)product["ProductName"],
UnitPrice = (decimal)product["UnitPrice"]
};
List<Product> products = query.ToList() as List<Product>;
lstProducts.DataContext = products;
}
VB
Private Sub ParseProducts_AsJson(ByVal sender As Object, _
ByVal e As DownloadStringCompletedEventArgs)
Dim raw As String = e.Result
Dim json As JsonArray
If TryCast(JsonArray.Parse(raw), JsonArray) Is Nothing Then
json = New JsonArray With _
{TryCast(JsonObject.Parse(raw), JsonObject)}
Else
json = TryCast(JsonArray.Parse(raw), JsonArray)
End If
Dim query = _
From product In json _
Select New Product With
{.ProductId = CInt(Fix(product("ProductId"))), _
.ProductName = CStr(product("ProductName")), _
.UnitPrice = CDec(product("UnitPrice"))}
Dim products As List(Of Product) = _
TryCast(query.ToList(), List(Of Product))
lstProducts.DataContext = products
End Sub
If there is a better way, I am certainly open to it. I’d love to see some additional methods on these objects to allow a little more variation. But overall I am thrilled to see LINQ to JSON! Now, too bad I can’t create an anonymous type from this LINQ query and bind it to the XAML. Wishes and dream for the next version :)