Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selectively read part of JSON data using JsonSerializer and populate a c# object

I connect to a 3rd party webservice that returns a complex JSON object that only contains a few bits of information I actually need.

Basically, I just need the array in "value". From that array, I just need the "Id", "Title" and "Status" properties.

I want to put those attributes into a c# class called Project. This is my class:

public class Project
{
    public String Id { get; set; }
    public String Title { get; set; }
    public String Status { get; set; }
}

I'm trying to use this code to read the JSON and do the transform:

using (WebResponse response = request.GetResponse())
{
    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    {
        var serializer = new JsonSerializer();
        var jsonTextReader = new JsonTextReader(reader);
        returnValue = serializer.Deserialize<Project>(jsonTextReader);
    }
}

Example JSON:

{
    "odata.metadata":"http://school.edu/Api/1/$metadata#Projects",
    "odata.count":"3",
    "value":[
        {
            "odata.id":"http://school.edu/Api/1/Projects('123')",
            "[email protected]":"http://school.edu/Api/1/Projects('123')/RelatedProjects",
            "[email protected]":"http://school.edu/Api/1/Projects('123')/Tags",
            "[email protected]":"http://school.edu/Api/1/Projects('123')/Categories",
            "[email protected]":"http://school.edu/Api/1/Projects('123')/ep",
            "#CreateLike":{
                    "target":"http://school.edu/Api/1/Projects('123')/CreateLike"
                  },
            "#CreateShortcut":{
                        "target":"http://school.edu/Api/1/Projects('123')/CreateShortcut"
                      },
            "#Play":{
                        "target":"http://school.edu/Play/123"
                      },
            "#SendInvitation":{
                        "target":"http://school.edu/Api/1/Projects('123')/SendInvitation"
                      },
            "#CopyProject":{
                        "target":"http://school.edu/Api/1/Projects('123')/CopyProject"
                      },
            "#AddVideoPodcast":{
                        "target":"http://school.edu/Api/1/Projects('123')/AddVideoPodcast"
                      },
            "#AddEP":{
                        "target":"http://school.edu/Api/1/Projects('123')/AddEP"
                      },
            "Id":"123",
            "Title":"Test Title 1",
            "Status":"Viewable"
        },
        {
            "odata.id":"http://school.edu/Api/1/Projects('456')",
            "[email protected]":"http://school.edu/Api/1/Projects('456')/RelatedProjects",
            "[email protected]":"http://school.edu/Api/1/Projects('456')/Tags",
            "[email protected]":"http://school.edu/Api/1/Projects('456')/Categories",
            "[email protected]":"http://school.edu/Api/1/Projects('456')/ep",
            "#CreateLike":{
                    "target":"http://school.edu/Api/1/Projects('456')/CreateLike"
                  },
            "#CreateShortcut":{
                        "target":"http://school.edu/Api/1/Projects('456')/CreateShortcut"
                      },
            "#Play":{
                        "target":"http://school.edu/Play/456"
                      },
            "#SendInvitation":{
                        "target":"http://school.edu/Api/1/Projects('456')/SendInvitation"
                      },
            "#CopyProject":{
                        "target":"http://school.edu/Api/1/Projects('456')/CopyProject"
                      },
            "#AddVideoPodcast":{
                        "target":"http://school.edu/Api/1/Projects('456')/AddVideoPodcast"
                      },
            "#AddEP":{
                        "target":"http://school.edu/Api/1/Projects('456')/AddEP"
                      },
            "Id":"456",
            "Title":"Test Title 2",
            "Status":"Viewable"
        },
        {
            "odata.id":"http://school.edu/Api/1/Projects('789')",
            "[email protected]":"http://school.edu/Api/1/Projects('789')/RelatedProjects",
            "[email protected]":"http://school.edu/Api/1/Projects('789')/Tags",
            "[email protected]":"http://school.edu/Api/1/Projects('789')/Categories",
            "[email protected]":"http://school.edu/Api/1/Projects('789')/ep",
            "#CreateLike":{
                    "target":"http://school.edu/Api/1/Projects('789')/CreateLike"
                  },
            "#CreateShortcut":{
                        "target":"http://school.edu/Api/1/Projects('789')/CreateShortcut"
                      },
            "#Play":{
                        "target":"http://school.edu/Play/789"
                      },
            "#SendInvitation":{
                        "target":"http://school.edu/Api/1/Projects('789')/SendInvitation"
                      },
            "#CopyProject":{
                        "target":"http://school.edu/Api/1/Projects('789')/CopyProject"
                      },
            "#AddVideoPodcast":{
                        "target":"http://school.edu/Api/1/Projects('789')/AddVideoPodcast"
                      },
            "#AddEP":{
                        "target":"http://school.edu/Api/1/Projects('789')/AddEP"
                      },
            "Id":"789",
            "Title":"Test Title 3",
            "Status":"Viewable"
        }
  ],
  "odata.nextLink":"http://school.edu/Api/1/Folders('xyz')/Projects?$skip=10&$top=10"
}

I just get a null object back. But in the debugger, I can see that it's pulling all the JSON data from the webservice.

How can I get what I need from the JSON, build my c# objects, and ignore all the rest?

like image 926
SkyeBoniwell Avatar asked Sep 28 '15 20:09

SkyeBoniwell


1 Answers

If you can use Json.NET (Newtonsoft json), you can utilize Linq-to-Json like this [1]

//using Newtonsoft.Json.Linq;
var jsonString = File.ReadAllText(@"C:YourDirectory\file.json"); //source
var projects = new List<Project>(); //Your result

JObject data = JObject.Parse(jsonString);
foreach (var value in data["value"])
{
    projects.Add(new Project
    {
        Id = value["Id"].ToString(),
        Status = value["Status"].ToString(),
        Title = value["Title"].ToString()
    });
}

Or, you can also deserialize the JObject like this [2]

var jsonReader = data["value"].CreateReader();
projects = new JsonSerializer().Deserialize<List<Project>>(jsonReader);

Both works just fine, but which one is better?

The second approach means less code (specially, if you have many properties in Project class, you'll have to write many lines of code to map each properties in code [1]).

But the performance of the first approach is many times better! For the given json data, code [1] runs roughly in 1 ms while code [2] takes more than 100 ms!


Update

After input from James Newton-King (who wrote Json.NET :) , there is another even more elegant way of doing this [3]

projects = data["value"].ToObject<List<Project>>();

And guess what! This code [3] takes nearly half the time of approach [1]. So, from all perspectives, this has to be the best approach!

like image 63
Arghya C Avatar answered Nov 03 '22 21:11

Arghya C