Search code examples
c#jsonjson.netexpandoobjectidictionary

Allow multiple values for the same key when creating JSON using ExpandoObject and IDictionary


I am trying to create dynamic JSON using ExpandoObject and IDictionary.

During the dynamic creation of JSON there could be instances when the Name or Value would repeat. However when adding the repeated Name or Value to the ExpandoObject, it gives an error:

An item with the same key has already been added.

Below is my code snippet :

DataTable dt_MappedColumns = (DataTable)ViewState["MappedColumns"];
dynamic ManCols = new ExpandoObject();
var dictionary1 = (IDictionary<string, object>)ManCols;
foreach (DataRow dr in dt_MappedColumns.Rows)
{
     dictionary1.Add(dr["TColumnName"].ToString(), dr["AColumnName"].ToString());
}
string Manjson = Newtonsoft.Json.JsonConvert.SerializeObject(dictionary1);

The DataTable looks like this:

Sr.No TColumnName AColumnName
----- ----------- -----------
1     Apple       Lion
2     Orange      Tiger
3     Mango       Fox
4     Orange      Wolf

In the above table the first 3 Rows are added successfully into dictionary1; however, when we try to add the fourth Row, it gives the error.

My desired JSON structure for repeated values would look like this:

{"Apple":"Lion", "Orange":["Tiger","Wolf"], "Mango":"Fox"}

Is it possible to create this JSON structure from the table?


Solution

  • Sure this is possible. Inside your loop you just need to check whether the key already exists in the dictionary and take the appropriate action. There are three cases:

    • The key doesn't exist, so add it as you are doing now.
    • The key exists and the existing value is a string, in which case you need to replace it with a list containing the old string value and the new string value.
    • The key exists and the existing value is a list, in which case you just need to add the new string to the list.

    Here is what the code looks like:

    foreach (DataRow dr in dt_MappedColumns.Rows)
    {
        string key = dr["TColumnName"].ToString();
        string value = dr["AColumnName"].ToString();
    
        if (!dictionary1.ContainsKey(key))
        {
            // key does not already exist, so add it
            dictionary1.Add(key, value);
        }
        else
        {
            // key exists, get the existing value
            object existingValue = dictionary1[key];
    
            if (existingValue is string)
            {
                // replace the existing string value with a list
                dictionary1[key] = new List<string> { (string)existingValue, value }; 
            }
            else
            {
                // the existing value is a list, so add the new value to it
                ((List<string>)existingValue).Add(value);
            }
        }
    }
    

    Fiddle: https://dotnetfiddle.net/PERc0D