using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public class CustomContractResolver : DefaultContractResolver
readonly HashSet<Type> WrappedTypes = new HashSet<Type>();
public CustomContractResolver(IEnumerable<Type> wrappedTypes)
if (wrappedTypes == null)
throw new ArgumentNullException();
foreach (var type in wrappedTypes)
class VersionWrapperProvider<T> : IValueProvider
readonly IValueProvider baseProvider;
public VersionWrapperProvider(IValueProvider baseProvider)
if (baseProvider == null)
throw new ArgumentNullException();
this.baseProvider = baseProvider;
public object GetValue(object target)
return new VersionWrapper<T>(target, baseProvider);
public void SetValue(object target, object value) { }
class ReadOnlyVersionWrapperProvider<T> : IValueProvider
readonly IValueProvider baseProvider;
public ReadOnlyVersionWrapperProvider(IValueProvider baseProvider)
if (baseProvider == null)
throw new ArgumentNullException();
this.baseProvider = baseProvider;
public object GetValue(object target)
return new ReadOnlyVersionWrapper<T>(target, baseProvider);
public void SetValue(object target, object value) { }
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (WrappedTypes.Contains(property.PropertyType)
&& !(member.DeclaringType.IsGenericType
&& (member.DeclaringType.GetGenericTypeDefinition() == typeof(VersionWrapper<>) || member.DeclaringType.GetGenericTypeDefinition() == typeof(ReadOnlyVersionWrapper<>))))
var wrapperGenericType = (property.Writable ? typeof(VersionWrapper<>) : typeof(ReadOnlyVersionWrapper<>));
var providerGenericType = (property.Writable ? typeof(VersionWrapperProvider<>) : typeof(ReadOnlyVersionWrapperProvider<>));
var wrapperType = wrapperGenericType.MakeGenericType(new[] { property.PropertyType });
var providerType = providerGenericType.MakeGenericType(new[] { property.PropertyType });
property.PropertyType = wrapperType;
property.ValueProvider = (IValueProvider)Activator.CreateInstance(providerType, property.ValueProvider);
property.ObjectCreationHandling = ObjectCreationHandling.Reuse;
internal class VersionWrapper<T>
readonly IValueProvider baseProvider;
public VersionWrapper(object target, IValueProvider baseProvider)
this.baseProvider = baseProvider;
public int Version { get { return 1; } }
[JsonProperty(NullValueHandling = NullValueHandling.Include)]
return (T)baseProvider.GetValue(target);
baseProvider.SetValue(target, value);
internal class ReadOnlyVersionWrapper<T>
readonly IValueProvider baseProvider;
public ReadOnlyVersionWrapper(object target, IValueProvider baseProvider)
this.baseProvider = baseProvider;
public int Version { get { return 1; } }
[JsonProperty(NullValueHandling = NullValueHandling.Include)]
return (T)baseProvider.GetValue(target);
public string Content { get; set; }
public MyContent Prop { get; set; }
public MyContent GetOnlyProperty { get { return Prop; } }
static IContractResolver resolver = new CustomContractResolver(new[] { typeof(MyContent) });
public static void Test()
foreach (var content in Contents())
var wrap = new Wrap { Prop = content };
var settings = new JsonSerializerSettings
ContractResolver = resolver,
var json = JsonConvert.SerializeObject(wrap, Formatting.Indented, settings);
Console.WriteLine("\nSimple JSON: ");
Console.WriteLine(JsonConvert.SerializeObject(wrap));
Console.WriteLine("Wrapped JSON: ");
var wrap2 = JsonConvert.DeserializeObject<Wrap>(json, settings);
Assert.IsTrue(wrap.Prop == wrap2.Prop || wrap.Prop.Content == wrap2.Prop.Content);
Console.WriteLine("\nAll tests passed.");
static void TestPopulate()
Console.WriteLine("\nTesting populate...");
Prop = new MyContent { Content = "abc" },
Prop = new MyContent { Content = "def" },
var settings = new JsonSerializerSettings
ContractResolver = resolver,
var json = JsonConvert.SerializeObject(wrap1, settings);
JsonConvert.PopulateObject(json, wrap2, settings);
Assert.IsTrue(wrap2.Prop.Content == wrap1.Prop.Content);
static IEnumerable<MyContent> Contents()
new MyContent { Content = "abc" },
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: ");