Search code examples
c#jsonserializationjson.netjavascriptserializer

Json deserialization issues with Tuples?


I have a class I use for configuration that holds a 3 tuple of all integers.

public class Configuration
{
    public List<Tuple<int, int, int>> MyThreeTuple { get; set; }

    public Configuration()
    {
        MyThreeTuple = new List<Tuple<int, int, int>>();
        MyThreeTuple.Add(new Tuple<int, int, int>(-100, 20, 501));
        MyThreeTuple.Add(new Tuple<int, int, int>(100, 20, 864));
        MyThreeTuple.Add(new Tuple<int, int, int>(500, 20, 1286));
    }
}

This class is serialized into Json with System.Web.Script.Serialization as such

JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
String configJson = jsonSerializer.Serialize(config);
File.WriteAllText(configPath, configJson);

and then deserialized when the application is launched

String configJson = File.ReadAllText(configPath);
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer(); 
object jsonObject = jsonSerializer.Deserialize(configJson, typeof(ApplicationConfiguration));
appConfig = (Configuration)jsonObject;

My issue is that whenever I go to deserialize the Json an exception is thrown

System.MissingMethodException in System.Web.Extensions.dll 

With the message

No parameterless constructor defined for type of `System.Tuple`3 ....

This is what the produced Json for the tuple looks like

"MyThreeTuple":
 [
    {"Item1":-100,"Item2":20,"Item3":501},
    {"Item1":100,"Item2":20,"Item3":864},
    {"Item1":500,"Item2":20,"Item3":1286}
 ]

Any idea how to solve this problem?

EDIT:

As other have suggested I tried out JSon.NET and it seems to work to deserialize the json. Though I have found an odd quirk.

So the constructor for my Configuration class fills in default values for the configuration. Specifically what is given in the code above. I have found that I can serialize the configuration with different values, but when deserialized, the default values are also loaded to the List<Tuple<>>.

I assume the Json.Net gets around the issue of Tuple not having a parameterless constructor by first instantiating Configuration and then setting its values.

It seems to be instantiating the class, then List.Adding the Tuples it finds in the json to the list. Instead of clearing the list then adding what it finds.

Is there an option in JSon.Net to solve this issue?


Solution

  • The reason why you got this error because JavascriptSerializer requires a public parameter-less constructor which is not the case for Tuple because it's an immutable

    take a look here http://json.codeplex.com/ for full comparison between javascriptserializer and json.net

    Even microsoft states in the documentation

    Json.NET should be used serialization and deserialization. Provides serialization and deserialization functionality for AJAX-enabled applications.

    here an example on how you can easily use JsonConvert to achieve this

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Newtonsoft.Json;
    
    namespace ConsoleApplication25
    {
        class Program
        {
            static void Main(string[] args)
            {
                Configuration configuration = new Configuration();
                string configJson = JsonConvert.SerializeObject(configuration);
                File.WriteAllText(configPath, configJson);
                //Deserialize the  content after you read your file in string 
    
                 var   configurationDeserialized = JsonConvert.DeserializeObject<Configuration>(configJson); 
    
    
    
            }
        }
    }
    
    public class Configuration
    {
         [JsonIgnore]
        public List<Tuple<int, int, int>> MyThreeTuple { get; set; }
    
        public Configuration()
        {
            MyThreeTuple = new List<Tuple<int, int, int>>();
            MyThreeTuple.Add(new Tuple<int, int, int>(-100, 20, 501));
            MyThreeTuple.Add(new Tuple<int, int, int>(100, 20, 864));
            MyThreeTuple.Add(new Tuple<int, int, int>(500, 20, 1286));
        }
    }