LINQ to JSON – Checking for an Object or Array

Sunday, September 14 2008 - , , ,

 

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 :)

DotNetKicks Image

6 comment(s)

Pingback from Dew Drop - September 15, 2008 | Alvin Ashcraft's Morning Dew

Pingback from Data Access Topics in Silverlight with John Papa

Hi John,

Nice example, but why not refactor it a little:

JsonArray json = JsonArray.Parse(raw) as JsonArray;

if (json == null)

{

json = new JsonArray {JsonObject.Parse(raw) as JsonObject};

}

That way you don't get to call 'JsonArray.Parse(raw) as JsonArray' twice.

Regards,

Boyan

i feel lucky can read this usefull news. now i find something what i want to know..

thank you for this great informations..

great post john :)

It was very dificult for me to have deal with array, but after reading your great post, it is more easy for me. Thanks!