using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
static string GetJsonSingle()
""EventMessageUId"": ""ef51b5a3-32b2-e611-baf9-fc3fdb446bd2"",
""Message"": ""{\""StoryId\"":20500,\""StoryDesc\"":\""Test Story data\""}"",
static string GetJsonMultiple()
""EventMessageUId"": ""ef51b5a3-32b2-e611-baf9-fc3fdb446bd2"",
""Message"": ""[{\""StoryId\"":20500,\""StoryDesc\"":\""Test Story data\""},{\""StoryId\"":99500,\""StoryDesc\"":\""second Test Story data\""}]"",
internal static void Test()
Console.WriteLine("Done");
private static void Test(string json)
Console.WriteLine("Testing: ");
var settings = new JsonSerializerSettings
Converters = { new StringConverterDecorator(new SingleOrArrayConverter<List<Message>, Message>()) },
var requirement = JsonConvert.DeserializeObject<Requirments>(json, settings);
Console.WriteLine("Deserialized Message: ");
Console.WriteLine(JsonConvert.SerializeObject(requirement.Message));
Console.WriteLine("Deserialized and re-serialized {0}: ", requirement);
Console.WriteLine(JsonConvert.SerializeObject(requirement, Formatting.Indented, settings));
public int FileID { get; set; }
public string EventMessageUId { get; set; }
public string ProjectId { get; set; }
public List<Message> Message { get; set; }
public string error { get; set; }
public string StoryID { get; set; }
public string StoryDesc { get; set; }
public class SingleOrArrayConverter<TCollection, TItem> : SingleOrArrayConverter where TCollection : ICollection<TItem>
public override bool CanConvert(Type objectType)
if (!base.CanConvert(objectType))
return typeof(TCollection).IsAssignableFrom(objectType);
public class SingleOrArrayConverter : JsonConverter
public override bool CanConvert(Type objectType)
if (objectType.IsArray || objectType == typeof(string) || objectType.IsPrimitive)
foreach (var type in objectType.GetCollectItemTypes())
return elementType != null;
object ReadJsonGeneric<TItem>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
if (reader.TokenType == JsonToken.Null)
var collection = (ICollection<TItem>)(existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
if (reader.TokenType == JsonToken.StartArray)
serializer.Populate(reader, collection);
collection.Add(serializer.Deserialize<TItem>(reader));
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
if (reader.TokenType == JsonToken.Null)
throw new JsonSerializationException("Read-only collections such as arrays are not supported");
var elementType = objectType.GetCollectItemTypes().SingleOrDefault();
throw new JsonSerializationException(string.Format("{0} is not an ICollection<T> for some T", objectType));
var method = typeof(SingleOrArrayConverter).GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
return method.MakeGenericMethod(new[] { elementType }).Invoke(this, new object[] { reader, objectType, existingValue, serializer });
throw new JsonSerializationException("Failed to deserialize " + objectType, ex);
void WriteJsonGeneric<TItem>(JsonWriter writer, object value, JsonSerializer serializer)
var list = (ICollection<TItem>)value;
foreach (object item in list)
serializer.Serialize(writer, item);
writer.WriteStartArray();
foreach (var item in list)
serializer.Serialize(writer, item);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
var objectType = value.GetType();
var elementType = objectType.GetCollectItemTypes().SingleOrDefault();
throw new JsonSerializationException(string.Format("{0} is not an ICollection<T> for some T", objectType));
var method = typeof(SingleOrArrayConverter).GetMethod("WriteJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
method.MakeGenericMethod(new[] { elementType }).Invoke(this, new object[] { writer, value, serializer });
throw new JsonSerializationException("Failed to serialize " + objectType, ex);
public static class TypeExtensions
public static IEnumerable<Type> GetInterfacesAndSelf(this Type type)
throw new ArgumentNullException();
return new[] { type }.Concat(type.GetInterfaces());
return type.GetInterfaces();
public static IEnumerable<Type> GetCollectItemTypes(this Type type)
foreach (Type intType in type.GetInterfacesAndSelf())
if (intType.IsGenericType
&& intType.GetGenericTypeDefinition() == typeof(ICollection<>))
yield return intType.GetGenericArguments()[0];
public class StringConverterDecorator : JsonConverterDecorator
public StringConverterDecorator(Type jsonConverterType) : base(jsonConverterType) { }
public StringConverterDecorator(JsonConverter converter) : base(converter) { }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
if (reader.TokenType == JsonToken.Null)
var s = JToken.Load(reader).ToString();
var token = JToken.Parse(s);
using (var subReader = token.CreateReader())
while (subReader.TokenType == JsonToken.None)
return base.ReadJson(subReader, objectType, existingValue, serializer);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
using (var textWriter = new StringWriter())
using (var subWriter = new JsonTextWriter(textWriter))
base.WriteJson(subWriter, value, serializer);
s = textWriter.ToString();
public abstract class JsonConverterDecorator : JsonConverter
readonly JsonConverter converter;
public JsonConverterDecorator(Type jsonConverterType) : this((JsonConverter)Activator.CreateInstance(jsonConverterType)) { }
public JsonConverterDecorator(JsonConverter converter)
throw new ArgumentNullException();
this.converter = converter;
public override bool CanConvert(Type objectType)
return converter.CanConvert(objectType);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
return converter.ReadJson(reader, objectType, existingValue, serializer);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
converter.WriteJson(writer, value, serializer);
public override bool CanRead { get { return converter.CanRead; } }
public override bool CanWrite { get { return converter.CanWrite; } }
public static void Main()
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);