Dynamically Building JSON Tree For Use In Javascript Components Using C#

These days, many JavaScript components use JSON when it comes to working with data, the reason is obvious enough, but some components that build some kind of tree structure like this one, are going to need a JSON tree. Building a static JSON tree is easy, but how do you build a dynamic JSON tree and pass them to the components like the one mentioned? That’s what this post is all about.

First Step: Building The Representation Of A Tree As A Type

The first step we need to take, is to build a tree in C#, and then convert that tree into a JSON tree. But we probably have a tree structure somewhere in the database, the structure I saw most of the time to represent tree in a database is a record with an Id and a ParentId, so I’m going to use that as the representation of my tree in the database, but since we don’t have any database, an In memory collection can serve our purpose, our collection is something like this:


   public class Cate
   {
      public int Id { get; set; }
      public int? ParentId { get; set; }
      public string Name { get; set; }
   }

   var cats = new List<Cate>
    {
        new Cate {Id = 1, ParentId = null, Name = "First"},
        new Cate {Id = 2, ParentId = null, Name = "Second"},
        new Cate {Id = 3, ParentId = null, Name = "Thrid"},
        new Cate {Id = 4, ParentId = null, Name = "Fourth"},
        new Cate {Id = 5, ParentId = 4, Name = "SubFourth1"},
        new Cate {Id = 6, ParentId = 4, Name = "SubFourth2"},
        new Cate {Id = 7, ParentId = 5, Name = "Sub_SubFourth1"},
        new Cate {Id = 8, ParentId = null, Name = "Sixth"},
        new Cate {Id = 9, ParentId = null, Name = "Seventh"},
        new Cate {Id = 10, ParentId = 9, Name = "SubSeventh1"},
        new Cate {Id = 11, ParentId = 9, Name = "SubSeventh2"},
        new Cate {Id = 12, ParentId = null, Name = "Eighth"},
        new Cate {Id = 13, ParentId = null, Name = "Ninth"},
        new Cate {Id = 14, ParentId = null, Name = "Tenth"},
        new Cate {Id = 15, ParentId = null, Name = "Eleventh"},
        new Cate {Id = 16, ParentId = 15, Name = "SubEleventh"},
        new Cate {Id = 17, ParentId = 16, Name = "Sub_SubEleventh"},
    };

Now we have the data we need for building a tree, what we need next is a type to represent our tree, every tree consists of many nodes, so we need to describe our node here, our type would be something like this:

    class Node
    {
        [JsonProperty(PropertyName = "nodes")]
        public List Children = new List();

        public bool ShouldSerializeChildren()
        {
            return (Children.Count > 0);
        }

        //[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public Node Parent { get; set; }
        public int Id { get; set; }
        public int? ParentId { get; set; }

        [JsonProperty(PropertyName = "text")]
        public string Name { get; set; }
    }

To better understand our Node class, let’s take a look at this tree image:

Every Node has a parent, so we declare a property of the type Node called Parent. In every Node, we have some data, which in this case is Id and ParentId and Name, and also, a Node can have many nodes as children, so we declared a property called Children that holds a list of Nodes as its children, and since we use Json.NET for our conversion form C# tree structure to JSON, ShouldSerializeChildren is responsible for something called “Conditional Property Serialization“, we need this because if we had a Node Without Children, The default behavior of Json.NET is that it includes this in our tree as empty collection of Nodes like this: “nodes”: [], and finally we have couple of Attributes that isn’t doing anything here except changing the name of our property in serialization.

Second Step: Filling The Tree With Data

Now we have all the types necessary to build a simple tree, what we need to do now is to fill our tree structure with data, I’ve found a method for that here, and changed it slightly to fit my need:

       public IEnumerable RawCollectionToTree(List collection)
        {
            var treeDictionary = new Dictionary<int?, Node>();

            collection.ForEach(x => treeDictionary.Add(x.Id, new Node { Id = x.Id, ParentId = x.ParentId, Name = x.Name }));

            foreach (var item in treeDictionary.Values)
            {
                if (item.ParentId != null)
                {
                    Node proposedParent;

                    if (treeDictionary.TryGetValue(item.ParentId, out proposedParent))
                    {
                        item.Parent = proposedParent;

                        proposedParent.Children.Add(item);
                    }
                }
                
            }
            return treeDictionary.Values.Where(x => x.Parent == null);
        }

Here we’ve built a dictionary called treeDictionary and we filled this dictionary with our data, key of this dictionary will be the Id of our Cate type and the value will be the data of the node. After we filled our dictionary, it’s time to assign the node’s Parent and Children property to its corresponding Parent and Children in the dictionary, here we foreach through our dictionary and if our node had a ParentId, we go ahead and get that Parent, and assign it to our current node’s (item) Parent property, and add to the Parent (proposedParent) its Children, which here is our Item, and return the dictionary where Parent is null, now we have a tree in C#:

Now we need to convert this tree to JSON.

Third Step: Converting C# Tree To JSON Tree

Last step and the easiest, is to convert our C# tree to JSON, but there are a couple of issues you might face, which I’ll explain next, for conversion we use this code:

         var tree= roots.RawCollectionToTree(cats).ToList();

         string json = JsonConvert.SerializeObject(tree, Formatting.Indented,
                new JsonSerializerSettings
                {
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                    NullValueHandling = NullValueHandling.Ignore
                });

Here, we first use our RawCollectionToTree method to build a tree form our collection, then we convert it into JSON, there are two other things which might be worth pointing out, here we use a JsonSerializerSettings with two properties, the first ReferenceLoopHandling is responsible for ignoring the Self referencing looping, which can cause stackoverflow exception, and the second one which is kind of obvious is the null value serialization, we tell the serializer to ignore the null values. Now we have a JSON tree which resembles something like this:

[
  {
    "Id": 1,
    "text": "First"
  },
  {
    "Id": 2,
    "text": "Second"
  },
  {
    "Id": 3,
    "text": "Thrid"
  },
  {
    "nodes": [
      {
        "nodes": [
          {
            "Id": 7,
            "ParentId": 5,
            "text": "Sub_SubFourth1"
          }
        ],
        "Id": 5,
        "ParentId": 4,
        "text": "SubFourth1"
      },
      {
        "Id": 6,
        "ParentId": 4,
        "text": "SubFourth2"
      }
    ],
    "Id": 4,
    "text": "Fourth"
  },
  {
    "Id": 8,
    "text": "Sixth"
  },
  {
    "nodes": [
      {
        "Id": 10,
        "ParentId": 9,
        "text": "SubSeventh1"
      },
      {
        "Id": 11,
        "ParentId": 9,
        "text": "SubSeventh2"
      }
    ],
    "Id": 9,
    "text": "Seventh"
  },
  {
    "Id": 12,
    "text": "Eighth"
  },
  {
    "Id": 13,
    "text": "Ninth"
  },
  {
    "Id": 14,
    "text": "Tenth"
  },
  {
    "nodes": [
      {
        "nodes": [
          {
            "Id": 17,
            "ParentId": 16,
            "text": "Sub_SubEleventh"
          }
        ],
        "Id": 16,
        "ParentId": 15,
        "text": "SubEleventh"
      }
    ],
    "Id": 15,
    "text": "Eleventh"
  }
]

You can download the sample project from here.

Share...
 

Hamid Mosalla

Hi, I'm Hamid Mosalla, I'm a software developer, indie cinema fan and a classical music aficionado. Here I write about my experiences mostly related to web development and .Net.