using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.ComponentModel;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public class TypeConverterJsonConverter : JsonConverter
readonly TypeConverter converter;
public TypeConverterJsonConverter(Type typeConverterType) : this((TypeConverter)Activator.CreateInstance(typeConverterType)) { }
public TypeConverterJsonConverter(TypeConverter converter)
throw new ArgumentNullException();
this.converter = converter;
public override bool CanConvert(Type objectType)
return converter.CanConvertFrom(typeof(string)) && converter.CanConvertTo(objectType);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
var tokenType = reader.SkipComments().TokenType;
if (tokenType == JsonToken.Null)
if (!tokenType.IsPrimitive())
throw new JsonSerializationException(string.Format("Token {0} is not primitive.", tokenType));
var s = (string)JToken.Load(reader);
return converter.ConvertFrom(null, CultureInfo.InvariantCulture, s);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
var s = converter.ConvertToInvariantString(value);
public static partial class JsonExtensions
public static JsonReader SkipComments(this JsonReader reader)
while (reader.TokenType == JsonToken.Comment && reader.Read())
public static bool IsPrimitive(this JsonToken tokenType)
case JsonToken.Undefined:
public class PropertyTypeConverterContractResolver : DefaultContractResolver
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
var property = base.CreateProperty(member, memberSerialization);
if (property.Converter == null)
var attr = property.AttributeProvider.GetAttributes(typeof(TypeConverterAttribute), false)
.OfType<TypeConverterAttribute>()
var typeConverterType = GetTypeFromName(attr.ConverterTypeName, member.DeclaringType.Assembly);
if (typeConverterType != null)
var jsonConverter = new TypeConverterJsonConverter(typeConverterType);
if (jsonConverter.CanConvert(property.PropertyType))
property.Converter = jsonConverter;
property.MemberConverter = jsonConverter;
static Type GetTypeFromName(string typeName, Assembly declaringAssembly)
if (string.IsNullOrEmpty(typeName))
Type typeFromGetType = Type.GetType(typeName);
Type typeFromComponent = null;
if (declaringAssembly != null)
if ((typeFromGetType == null) ||
(declaringAssembly.FullName.Equals(typeFromGetType.Assembly.FullName)))
int comma = typeName.IndexOf(',');
typeName = typeName.Substring(0, comma);
typeFromComponent = declaringAssembly.GetType(typeName);
return typeFromComponent ?? typeFromGetType;
[TypeConverter(typeof(CidNumberConvertor))]
[JsonProperty("cid_number")]
public Cid CidNumber { get; set; }
[TypeConverter(typeof(CidHexaConvertor))]
[JsonProperty("cid_hexa")]
[JsonProperty("cid_default")]
public override string ToString()
return Id.ToString(NumberFormatInfo.InvariantInfo);
public abstract class CidConvertorBase : TypeConverter
protected abstract long ToInt64(string value, System.Globalization.CultureInfo culture);
protected abstract string FromInt64(long value, System.Globalization.CultureInfo culture);
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
if (sourceType == typeof(string))
return base.CanConvertFrom(context, sourceType);
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
if (destinationType == typeof(Cid))
return base.CanConvertTo(context, destinationType);
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
return new Cid(ToInt64((string)value, culture));
return base.ConvertFrom(context, culture, value);
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
if (destinationType == typeof(string) && value is Cid)
return FromInt64(((Cid)value).Id, culture);
return base.ConvertTo(context, culture, value, destinationType);
public class CidNumberConvertor : CidConvertorBase
protected override long ToInt64(string value, CultureInfo culture)
return long.Parse(value, culture);
protected override string FromInt64(long value, CultureInfo culture)
return value.ToString(culture);
public class CidHexaConvertor : CidConvertorBase
protected override long ToInt64(string value, CultureInfo culture)
return Convert.ToInt64(value, 16);
protected override string FromInt64(long value, CultureInfo culture)
return value.ToString("x", culture);
public static void Test()
CidDefault = new Cid(101),
CidNumber = new Cid(303),
var resolver = new PropertyTypeConverterContractResolver();
var settings = new JsonSerializerSettings
ContractResolver = resolver,
var json = JsonConvert.SerializeObject(root, Formatting.Indented, settings);
Console.WriteLine("Serialized {0}", root);
var root2 = JsonConvert.DeserializeObject<JsonModel>(json, settings);
Assert.IsTrue(root.CidHexa.Id == root2.CidHexa.Id, "root.CidHexa.Id == root2.CidHexa.Id");
Assert.IsTrue(root.CidNumber.Id == root2.CidNumber.Id, "root.CidNumber.Id == root2.CidNumber.Id");
Assert.IsTrue(root.CidDefault.Id == root2.CidDefault.Id, "root.CidDefault.Id == root2.CidDefault.Id");
var json2 = JsonConvert.SerializeObject(root2, Formatting.Indented, settings);
Assert.IsTrue(JToken.DeepEquals(JToken.Parse(json), JToken.Parse(json2)));
public static void Main()
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");