2

I have following class definition:

public class ElasticObject : Dictionary<string, object>
{
    public int Id { get;set;}
}

var keyValues = new ElasticObject();
keyValues.Id= 200000;
keyValues.Add("Price", 12.5);
var json = JsonConvert.SerializeObject(keyValues,
           new JsonSerializerSettings{NullValueHandling = NullValueHandling.Ignore});

The parsed json string is {"Price":12.5} which fails to contain the Id property, is there any way to customize the json conversion?

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
sunqiang.leo
  • 235
  • 3
  • 7

2 Answers2

2

You can do this by making a custom JsonConverter class. Perhaps something like this:

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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        ElasticObject eobj = (ElasticObject)value;
        var temp = new Dictionary<string, object>(eobj);
        temp.Add("Id", eobj.Id);
        serializer.Serialize(writer, temp);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var temp = serializer.Deserialize<Dictionary<string, object>>(reader);
        ElasticObject eobj = new ElasticObject();
        foreach (string key in temp.Keys)
        {
            if (key == "Id")
                eobj.Id = Convert.ToInt32(temp[key]);
            else
                eobj.Add(key, temp[key]);
        }
        return eobj;
    }
}

You would then use it like this:

var settings = new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore,
    Converters = new List<JsonConverter> { new ElasticObjectConverter() }
};

var keyValues = new ElasticObject();
keyValues.Id = 200000;
keyValues.Add("Price", 12.5);

var json = JsonConvert.SerializeObject(keyValues, settings);

The JSON produced by the above would look like this:

{"Price":12.5,"Id":200000}

Is this what you are looking for?

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
0

I made the extra properties just poke data back in to the base dictionary instead. This way you get to expose a property like "Id" but during serialisation/de-serialisation it will just work with the underlying dictionary:

public class ElasticObject : Dictionary<string, object>
{
    public int Id
    {
        get { 
            int val;
            if (int.TryParse(this["Id"] as string, out val))
            {
                return val;
            }

            return -1;
        }
        set { this["Id"] = value; }
    }
}
Eddie Fletcher
  • 2,823
  • 2
  • 21
  • 23
  • 1
    Please note: because JSON.NET will [bypass your setters and directly set the "underlying" dictionary](http://www.newtonsoft.com/json/help/html/SerializationGuide.htm#Dictionarys) it won't 'strongly type' the values, and so if any of your properties are classes they'll end up as `JArrays` or `JObject`. As you already pointed out, you basically have to "deserialize" it again in each getter, which is not ideal. – drzaus May 21 '15 at 16:35