Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build object hierarchy for serialization with json.net?

I'm trying to properly write code to build a data structure to serialize into json.

I'm using json.net.

I don't want to create a bunch of classes to hold this data, as I thought there should be some classes that will already do this in json.net

I've already got all the data I need in a series of nested loops, and now I just want to add them to an object hierarchy before I run JsonConvert.SerializeObject on it.

I've already tried code like this, but it doesn't seem to work

JArray container = new JArray();

        container.Add(new JObject(new JProperty("name", "Client1"), new JProperty("projects", new JArray())));

        container[0].AddAfterSelf(new JObject(new JProperty("projects", new JArray())));            
        container[1].AddAfterSelf(new JObject(new JProperty("projects", "Project2")));
        container[1].AddAfterSelf(new JObject(new JProperty("projects", "Project3")));
        container.Add(new JProperty("name", "Client2"));            

        var test = JsonConvert.SerializeObject(container);

The problem is that when I use [i]. or ElementAt(i) to access somewhere in the structure, either .Add() is missing or .ElementAt isn't there. How do I step through the data structure to make this nicely output the below, or do I have to create my own container class for all of this?

This is the data format I am trying to make.

[
    {
    "name": "student1",
    "projects": 
    [
        {
        "name": "Project1",
        "tasks": 
                [
                    {
                    "name": "task1",
                    "id": 2
                    }
                ],
        "id": 6
        }
    ]
},
    {
    "name": "Student2",
    "projects": [
                {
                "name": "Project1",
                "tasks": [
                         {
                         "name": "Task2",
                         "id": 1
                         },
                         {
                         "name": "Task3",
                         "id": 3
                         },
                         {
                         "name": "Task4",
                         "id": 4
                         }
                         ],
                "id": 2

etc...

like image 741
Chris Barry Avatar asked May 12 '11 13:05

Chris Barry


3 Answers

I think what you're asking is how to serialize complex business objects in json, but only expose certain properties.

In other words you already have a list of students, but you only want to send very specific data via json. If I'm wrong this answer won't suit your needs.

So assuming you have a list of students, with a projects property that has an inner property of tasks, this is how I do it without having to create loads of new classes, I use anonymous objects.

Once I've created my list of anonymous objects, I simply turn them into a json string.

As pointed out in the comments you don't need to use json.net, this functionality is available in the framework, add a reference to System.Web.Extensions.dll then

using System.Web.Script.Serialization;

var jsonStudents = new List<object>();

foreach (var student in students)
{
    jsonStudents.Add(new
    {
        student.Id,         //anonymous properties automatically pick up the name of the property you pass them, this will be called Id
        FullName = student.FirstName + " " + student.LastName, //if you want to name a property yourself use this notation
        Projects = student.Projects.Select(p => new //this will be an enumerable of nested anonymous objects, we're partially selecting project properties
        {
            p.Id,
            p.Name,
            Tasks = p.Tasks.Select(t => new //nesting another level
            {
                t.Id,
                t.Name
            })
        })
    });
}

var serializer = new JavaScriptSerializer();

var jsonString = serializer.Serialize(jsonStudents);

If you really want to use loops you can do this to allow you to do more complicated things in the creating of the projects and tasks:

var jsonStudents = new List<object>();

foreach (var student in students)
{
    var tempStudent = new
    {
        student.Id,         //anonymous properties automatically pick up the name of the property you pass them, this will be called Id
        FullName = student.FirstName + " " + student.LastName, //if you want to name a property yourself use this notation
        Projects = new List<object>()
    };

    foreach (var project in student.Projects)
    {
        var tempProject = new {
            project.Id,
            project.Name,
            Tasks = new List<object>()
        };

        foreach (var task in project.Tasks)
        {
            tempProject.Tasks.Add(new {
                task.Id,
                task.Name
            });
        }

        tempStudent.Projects.Add(tempProject);
    }

    jsonStudents.Add(tempStudent);
}

var serializer = new JavaScriptSerializer();

var jsonString = serializer.Serialize(jsonStudents);
like image 93
mattmanser Avatar answered Nov 09 '22 14:11

mattmanser


this is the code which generates the exact output from your question (requires a using Newtonsoft.Json.Linq;):

var json = new JArray(
                new JObject(
                    new JProperty("name", "student1"),
                    new JProperty("projects", 
                        new JArray(
                            new JObject(
                                new JProperty("name", "Project1"),
                                new JProperty("tasks", 
                                    new JArray(
                                        new JObject(
                                            new JProperty("name", "task1"),
                                            new JProperty("id", 2)
                                            )
                                        )
                                    ),
                                new JProperty("id", 6)
                            )
                        )
                    )
                ),
                new JObject(
                    new JProperty("name", "student2"),
                    new JProperty("projects", 
                        new JArray(
                            new JObject(
                                new JProperty("name", "Project1"),
                                new JProperty("tasks", 
                                    new JArray(
                                        new JObject(
                                            new JProperty("name", "task2"),
                                            new JProperty("id", 1)
                                            ),
                                        new JObject(
                                            new JProperty("name", "task3"),
                                            new JProperty("id", 3)
                                            ),
                                        new JObject(
                                            new JProperty("name", "task4"),
                                            new JProperty("id", 4)
                                            )
                                        )
                                    ),
                                new JProperty("id", 2)
                            )
                        )
                    )
                )
            );
var jsonString = json.ToString();

I believe using the Json.Net Linq syntax has the great advantage that the resulting C# code can be formatted so that it almost has the same structure as the JSON you're trying to generate.

UPDATE

If you want to manipulate the Json object once it has been built, look at this example which builds the outer array with only one student, and then appends another one:

// create an isolated Student instance:
var student2 = new JObject(
                    new JProperty("name", "student2"),
                    new JProperty("projects", 
                        new JArray(
                            new JObject(
                                new JProperty("name", "Project1"),
                                new JProperty("tasks", 
                                    new JArray(
                                        new JObject(
                                            new JProperty("name", "task2"),
                                            new JProperty("id", 1)
                                            ),
                                        new JObject(
                                            new JProperty("name", "task3"),
                                            new JProperty("id", 3)
                                            ),
                                        new JObject(
                                            new JProperty("name", "task4"),
                                            new JProperty("id", 4)
                                            )
                                        )
                                    ),
                                new JProperty("id", 2)
                            )
                        )
                    )
                );

var json = new JArray(
                new JObject(
                    new JProperty("name", "student1"),
                    new JProperty("projects", 
                        new JArray(
                            new JObject(
                                new JProperty("name", "Project1"),
                                new JProperty("tasks", 
                                    new JArray(
                                        new JObject(
                                            new JProperty("name", "task1"),
                                            new JProperty("id", 2)
                                            )
                                        )
                                    ),
                                new JProperty("id", 6)
                            )
                        )
                    )
                )
            );

// now, add the student2 instance to the array:
json                             // which is an JArray
    .Last                        // gets the last Array item, i.e. "student1"
    .AddAfterSelf(student2);     // adds this which hence becomes the new last one

The idea is that you can apply the very same principle to any other portion of the structure in the same way.

HTH...

like image 11
mthierba Avatar answered Nov 09 '22 14:11

mthierba


In the end I have used these Models.

public class JStudent
{
    public List<JProject> projects = new List<JProject>();
    public string name;
    public string id;
}
public class JProject
{
    public List<JTask> tasks = new List<JTask>();
    public string name;
    public string id;
}
public class JTask
{
    public string name;
    public string id;

}

It is now working perfectly. Is there any better way to do this?

like image 5
Chris Barry Avatar answered Nov 09 '22 14:11

Chris Barry