Yesterday, a colleague of mine was having problems implementing a Web API microservice, where client was throwing the exception:
'Cannot create and populate list type System.Collections.Specialized.NameValueCollection. Path ...' on de-serialization of a complex graph containing NameValueCollections.
Web searches returned a number suggestions to replace the NameValueCollection with a dictionary, which did not work in our case, where we needed to use classes as is.
As I've created the initial reference architecture, I felt obliged to help resolve the issue. As said, Web searches for a solution didn't return anything closely applicable, I've taken a bit deeper look at the Json.NET library documentation, and shortly afterwards decided to create a custom converter.
It turned out to be easy. Here's the source code:
To user the converter, add it to the converters collection as follows:
'Cannot create and populate list type System.Collections.Specialized.NameValueCollection. Path ...' on de-serialization of a complex graph containing NameValueCollections.
Web searches returned a number suggestions to replace the NameValueCollection with a dictionary, which did not work in our case, where we needed to use classes as is.
As I've created the initial reference architecture, I felt obliged to help resolve the issue. As said, Web searches for a solution didn't return anything closely applicable, I've taken a bit deeper look at the Json.NET library documentation, and shortly afterwards decided to create a custom converter.
It turned out to be easy. Here's the source code:
/// <summary> /// Custom converter for (de)serializing NameValueCollection /// Add an instance to the settings Converters collection /// </summary> public class NameValueCollectionConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var collection = value as NameValueCollection; if (collection == null) return; writer.WriteStartObject(); foreach (var key in collection.AllKeys) { writer.WritePropertyName(key); writer.WriteValue(collection.Get(key)); } writer.WriteEndObject(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var nameValueCollection = new NameValueCollection(); var key = ""; while (reader.Read()) { if (reader.TokenType == JsonToken.StartObject) { nameValueCollection = new NameValueCollection(); } if (reader.TokenType == JsonToken.EndObject) { return nameValueCollection; } if (reader.TokenType == JsonToken.PropertyName) { key = reader.Value.ToString(); } if (reader.TokenType == JsonToken.String) { nameValueCollection.Add(key, reader.Value.ToString()); } } return nameValueCollection; } public override bool CanConvert(Type objectType) { return objectType == typeof(NameValueCollection); } }
To user the converter, add it to the converters collection as follows:
var settings = new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), TypeNameHandling = TypeNameHandling.All, Formatting = Formatting.Indented }; settings.Converters.Add(new NameValueCollectionConverter()); JsonConvert.DefaultSettings = () => settings;Nice job done in implementing and documenting Json.NET!