Serialize json for an object with a catch of all dictionary properties

I would like to use JSON.net to deserialize for an object, but put unnamed properties in a dictionary property. Is it possible?

For example, given json,

{one:1,two:2,three:3} 

and C # class:

 public class Mapped { public int One {get; set;} public int Two {get; set;} public Dictionary<string,object> TheRest {get; set;} } 

Can JSON.NET be deserialized to an instance with values ​​one = 1, two = 1, TheRest = Dictionary {{"three, 3}}

+6
source share
2 answers

You can create a CustomCreationConverter to do what you need to do. Here's a sample (quite ugly, but demonstrates how you can do this):

 namespace JsonConverterTest1 { public class Mapped { private Dictionary<string, object> _theRest = new Dictionary<string, object>(); public int One { get; set; } public int Two { get; set; } public Dictionary<string, object> TheRest { get { return _theRest; } } } public class MappedConverter : CustomCreationConverter<Mapped> { public override Mapped Create(Type objectType) { return new Mapped(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var mappedObj = new Mapped(); var objProps = objectType.GetProperties().Select(p => p.Name.ToLower()).ToArray(); //return base.ReadJson(reader, objectType, existingValue, serializer); while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName) { string readerValue = reader.Value.ToString().ToLower(); if (reader.Read()) { if (objProps.Contains(readerValue)) { PropertyInfo pi = mappedObj.GetType().GetProperty(readerValue, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); var convertedValue = Convert.ChangeType(reader.Value, pi.PropertyType); pi.SetValue(mappedObj, convertedValue, null); } else { mappedObj.TheRest.Add(readerValue, reader.Value); } } } } return mappedObj; } } public class Program { static void Main(string[] args) { string json = "{'one':1, 'two':2, 'three':3, 'four':4}"; Mapped mappedObj = JsonConvert.DeserializeObject<Mapped>(json, new MappedConverter()); Console.WriteLine(mappedObj.TheRest["three"].ToString()); Console.WriteLine(mappedObj.TheRest["four"].ToString()); } } } 

Thus, the output of mappedObj after deserializing the JSON string will be an object with its One and Two properties, and everything else will be in the Dictionary . Of course, I hard coded the values ​​of One and Two as int s, but I think this demonstrates how you do it.

Hope this helps.

EDIT : I updated the code to make it more general. I have not fully tested it, so in some cases when it fails, some problems may arise, but I think that you like it most.

+2
source

The easiest way to do this is to use the JsonExtensionData attribute to define a catch all dictionary.

An example from the Json.Net documentation :

 public class DirectoryAccount { // normal deserialization public string DisplayName { get; set; } // these properties are set in OnDeserialized public string UserName { get; set; } public string Domain { get; set; } [JsonExtensionData] private IDictionary<string, JToken> _additionalData; [OnDeserialized] private void OnDeserialized(StreamingContext context) { // SAMAccountName is not deserialized to any property // and so it is added to the extension data dictionary string samAccountName = (string)_additionalData["SAMAccountName"]; Domain = samAccountName.Split('\\')[0]; UserName = samAccountName.Split('\\')[1]; } public DirectoryAccount() { _additionalData = new Dictionary<string, JToken>(); } } string json = @"{ 'DisplayName': 'John Smith', 'SAMAccountName': 'contoso\\johns' }"; DirectoryAccount account = JsonConvert.DeserializeObject<DirectoryAccount>(json); Console.WriteLine(account.DisplayName); // John Smith Console.WriteLine(account.Domain); // contoso Console.WriteLine(account.UserName); // johns 
+1
source

Source: https://habr.com/ru/post/893592/


All Articles