Serializing an object array to JSON

36,261

In order to serialize your wrapper class such that its internal dictionary appears in the JSON as if the wrapper were not there, you need a custom JsonConverter. A JsonConverter gives you direct control over what gets serialized and/or deserialized for a particular class.

Below is a converter that should work for your case. Since you didn't really provide any details about your wrapper class other than it has a field called values to hold the dictionary, I used reflection to gain access to it. If your class has public methods to manipulate the dictionary directly, you can change the converter to use those methods instead, if you prefer. Here is the code:

class DictionaryWrapperConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(MyWrapper));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        MyWrapper wrapper = (MyWrapper)value;
        FieldInfo field = typeof(MyWrapper).GetField("values", BindingFlags.NonPublic | BindingFlags.Instance);
        JObject jo = JObject.FromObject(field.GetValue(wrapper));
        jo.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        MyWrapper wrapper = new MyWrapper();
        FieldInfo field = typeof(MyWrapper).GetField("values", BindingFlags.NonPublic | BindingFlags.Instance);
        field.SetValue(wrapper, jo.ToObject(field.FieldType));
        return wrapper;
    }
}

To tie the custom converter to your wrapper class, you can add a [JsonConverter] attribute to the class definition:

[JsonConverter(typeof(DictionaryWrapperConverter))]
class MyWrapper : IEnumerable
{
    Dictionary<string, string> values = new Dictionary<string, string>();

    public void Add(string key, string value)
    {
        values.Add(key, value);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return values.GetEnumerator();
    }
}

Here is a full demo showing the converter in action, first serializing and deserializing a single instance of the wrapper class, then serializing and deserializing a list of wrappers:

class Program
{
    static void Main(string[] args)
    {
        MyWrapper wrapper = new MyWrapper();
        wrapper.Add("foo", "bar");
        wrapper.Add("fizz", "bang");

        // serialize single wrapper instance
        string json = JsonConvert.SerializeObject(wrapper, Formatting.Indented);

        Console.WriteLine(json);
        Console.WriteLine();

        // deserialize single wrapper instance
        wrapper = JsonConvert.DeserializeObject<MyWrapper>(json);

        foreach (KeyValuePair<string, string> kvp in wrapper)
        {
            Console.WriteLine(kvp.Key + "=" + kvp.Value);
        }
        Console.WriteLine();
        Console.WriteLine("----------\n");

        MyWrapper wrapper2 = new MyWrapper();
        wrapper2.Add("a", "1");
        wrapper2.Add("b", "2");
        wrapper2.Add("c", "3");

        List<MyWrapper> list = new List<MyWrapper> { wrapper, wrapper2 };

        // serialize list of wrappers
        json = JsonConvert.SerializeObject(list, Formatting.Indented);

        Console.WriteLine(json);
        Console.WriteLine();

        // deserialize list of wrappers
        list = JsonConvert.DeserializeObject<List<MyWrapper>>(json);

        foreach (MyWrapper w in list)
        {
            foreach (KeyValuePair<string, string> kvp in w)
            {
                Console.WriteLine(kvp.Key + "=" + kvp.Value);
            }
            Console.WriteLine();
        }
    }
}

Output:

{
  "foo": "bar",
  "fizz": "bang"
}

foo=bar
fizz=bang

----------

[
  {
    "foo": "bar",
    "fizz": "bang"
  },
  {
    "a": "1",
    "b": "2",
    "c": "3"
  }
]

foo=bar
fizz=bang

a=1
b=2
c=3
Share:
36,261
alwayslearning
Author by

alwayslearning

Microsoft Certified Solutions Associate - Cloud Platform, with more than 15 years of experience in developing data driven solutions. Currently focused on everything Azure.

Updated on March 05, 2020

Comments

  • alwayslearning
    alwayslearning about 4 years

    I have a type which is a wrapper over a dictionary - basically a key/value store. I would like to serialize an array of objects of this type to JSON. I am pretty new to JSON and Json.NET (newtonsoft.json).

    My type has a method called - ToJson which serializes its dictionary to json as follows

    public string ToJson()
    {
      return JsonConvert.SerializeObject(this.values);
    }    
    

    And then I try to serialize an array of these objects

    var json = JsonConvert.SerializeObject(objectArray)
    

    Of course this does not work because each object in the array is serialized and I do not know how to direct the serialization process to my 'ToJson' method for each object.

    I can get it to work exactly as I want it if I pass in an array of Dictionary objects.

    Maybe I am missing some serialization attribute?

    EDIT:

    After reading some more documentation I tried a shorter way (before considering the JsonConverter approach) - using the 'JsonPropertyAttribute'. Applying it to the private Dictionary member almost did the job except that I also get the member name serialized, which I do not want. Any way to just serialize the member value and not the member name by using the JsonPropertyAttribute?

  • Brian Rogers
    Brian Rogers about 10 years
    This does not solve the problem posed in the question.