Answered by:
Deserialize JSON With Delimited String Directly to List Using TypeConverter

Question
-
User-691759321 posted
So, I have a JSON value as a string:
"[{"Purpose":"Internal; Product Selection"},{"Purpose":"Product Selection; Web"},{"Purpose":"Internal; Product Selection"}]"
I have a class designed to deserialize the JSON to (note this is a simplified class structure).
using Newtonsoft.Json; using System.Collections.Generic; using System.ComponentModel; public class Attribute { public string Purpose { get; set; } }
I am using Newtonsoft.Json version 9. Each Attribute.Purpose field is populated with semi-colon delimited list after the deserialization process. What I would prefer is to have Purpose be a List<string>. I did try to take in the value as a string and have a read-only property convert the string to a list. This works but is slow.
using Newtonsoft.Json; using System.Collections.Generic; using System.Linq; public class Attribute { [JsonProperty("Purpose")] public string _Purpose { get; set; } [JsonIgnore] public List<string> Purpose { get { return this._Purpose.Split(';').Select(x => x.Trim()).ToList(); } } }
I would like to use a TypeConverter but cannot seem to find one that work. I should mention that I am using Sitecore through a Solr ContentSearchManager query. Sitecore has provided some custom converters for index fields which do exactly what I want, however this is not an index field. The converter I use on the index field is Sitecore.ContentSearch.Converters.IndexFieldEnumerableConverter. I am looking for some way to handle this with standard .NET libraries or Newtonsoft.
Any ideas?
Friday, May 22, 2020 3:35 PM
Answers
-
User753101303 posted
You can put this attribute on the Purpose property only. For example :
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; namespace ConsoleDemo { public class DelimitedStringConverter : JsonConverter<List<string>> { public override void WriteJson(JsonWriter writer, List<string> value, JsonSerializer serializer) { throw new NotImplementedException(); } public override List<string> ReadJson(JsonReader reader, Type objectType, List<string> existingValue, bool hasExistingValue, JsonSerializer serializer) { string s = (string)reader.Value; if (string.IsNullOrEmpty(s)) { return new List<string>(); } return s.Split(';').Select(x => x.Trim()).ToList(); } } class Program { class Data { public string Name { get; set; } [JsonConverter(typeof(DelimitedStringConverter))]
public List<string> Purpose { get; set; }
} static void Main() { var str = @"{""Name"":""a; b"",""Purpose"":""a; b""}"; var data = JsonConvert.DeserializeObject<Data>(str); Console.WriteLine(data.Name); foreach (string value in data.Purpose) { Console.WriteLine("-{0}-", value); } } } }shows :
a; b
-a-
-b-- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, May 24, 2020 9:02 AM
All replies
-
User475983607 posted
The ideal solution is fixing the JSON format.
{"Purpose": ["Internal", "Product Selection"]}
Friday, May 22, 2020 3:44 PM -
User-691759321 posted
The simple response is that changing the format of Json is not an option. I know it is improper for the data type but I do not have control to fix it.Friday, May 22, 2020 3:49 PM -
User753101303 posted
Hi,
From a quick look it seems you could customize how this property is serialized/deserialized using https://www.newtonsoft.com/json/help/html/CustomJsonConverterGeneric.htm doing a string.Split when reading and a string.Join when writing.
Saturday, May 23, 2020 8:29 PM -
User-691759321 posted
While an interesting idea I am not sure how this would translate to my example. The code in that link seems to apply for custom classes only. Almost every field in my Product class is a string. I am not sure if a custom converter would know how to distinguish between a delimited list and a description that just happens to contain the same delimiter.
Saturday, May 23, 2020 9:24 PM -
User753101303 posted
You can put this attribute on the Purpose property only. For example :
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; namespace ConsoleDemo { public class DelimitedStringConverter : JsonConverter<List<string>> { public override void WriteJson(JsonWriter writer, List<string> value, JsonSerializer serializer) { throw new NotImplementedException(); } public override List<string> ReadJson(JsonReader reader, Type objectType, List<string> existingValue, bool hasExistingValue, JsonSerializer serializer) { string s = (string)reader.Value; if (string.IsNullOrEmpty(s)) { return new List<string>(); } return s.Split(';').Select(x => x.Trim()).ToList(); } } class Program { class Data { public string Name { get; set; } [JsonConverter(typeof(DelimitedStringConverter))]
public List<string> Purpose { get; set; }
} static void Main() { var str = @"{""Name"":""a; b"",""Purpose"":""a; b""}"; var data = JsonConvert.DeserializeObject<Data>(str); Console.WriteLine(data.Name); foreach (string value in data.Purpose) { Console.WriteLine("-{0}-", value); } } } }shows :
a; b
-a-
-b-- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, May 24, 2020 9:02 AM -
User-691759321 posted
I could not use JsonConverter<List<string>> because we are still using version 9 of Newtonsoft.Json and it does not support it. I was able to take that out and use the generic JsonConverter override to achieve what I wanted.
Thanks!
Tuesday, May 26, 2020 9:48 PM