Last active
September 10, 2017 17:21
-
-
Save grishace/40f606c05222808394608f65519aceb9 to your computer and use it in GitHub Desktop.
JSON deserialization with unknown properties accumulated in the dictionary
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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