Skip to content

Instantly share code, notes, and snippets.

@grishace
Last active September 10, 2017 17:21
Show Gist options
  • Select an option

  • Save grishace/40f606c05222808394608f65519aceb9 to your computer and use it in GitHub Desktop.

Select an option

Save grishace/40f606c05222808394608f65519aceb9 to your computer and use it in GitHub Desktop.
JSON deserialization with unknown properties accumulated in the dictionary
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
namespace JsonProperties
{
class PropertyBag
{
public Dictionary<string, string> Properties { get; set; }
public PropertyBag()
{
Properties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
}
class Message : PropertyBag
{
public long Id { get; set; }
public double Value { get; set; }
public string Status { get; set; }
}
class PropertyBagConverter : JsonConverter
{
public override bool CanConvert(Type T)
{
return T.IsSubclassOf(typeof(PropertyBag));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
existingValue = existingValue ?? Activator.CreateInstance(objectType, true);
var jObject = JObject.Load(reader);
var properties = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var props = new Dictionary<string, PropertyInfo>(properties.ToDictionary(k => k.Name, v => v), StringComparer.OrdinalIgnoreCase);
var missingProps = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var token in jObject)
{
PropertyInfo prop;
if (props.TryGetValue(token.Key, out prop))
{
dynamic val = token.Value.ToObject<object>();
prop.SetValue(existingValue, val, null);
}
else
{
missingProps.Add(token.Key.ToUpperInvariant(), token.Value.ToString());
}
}
var pb = existingValue as PropertyBag;
if (pb != null)
{
pb.Properties = missingProps;
}
return existingValue;
}
}
class Program
{
static void Main(string[] args)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Converters = {
new PropertyBagConverter()
}
};
var message = @"{
""id"" : 666,
""value"" : 123.456,
""status"" : ""200"",
""missing_property_1"" : [ ""a"", ""b"" ],
""missing_property_2"" : ""3"",
""missing_property_3"" : ""4"",
}";
var des = JsonConvert.DeserializeObject<Message>(message, settings);
Console.WriteLine(des.Id);
Console.WriteLine(des.Value);
Console.WriteLine(des.Status);
foreach (var prop in des.Properties)
{
Console.WriteLine("{0} : {1}", prop.Key, prop.Value);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment