using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System.Diagnostics;
[System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class LegacyDataMemberNamesAttribute : Attribute
public LegacyDataMemberNamesAttribute() : this(new string[0]) { }
public LegacyDataMemberNamesAttribute(params string[] names) { this.Names = names; }
public string [] Names { get; set; }
public class LegacyPropertyResolver : DefaultContractResolver
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
var properties = base.CreateProperties(type, memberSerialization);
for (int i = 0, n = properties.Count; i < n; i++)
var property = properties[i];
var attrs = property.AttributeProvider.GetAttributes(typeof(LegacyDataMemberNamesAttribute), true);
if (attrs == null || attrs.Count == 0)
var clone = property.GetType().GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (var name in attrs.Cast<LegacyDataMemberNamesAttribute>().SelectMany(a => a.Names))
if (properties.Any(p => p.PropertyName == name))
Debug.WriteLine("Duplicate LegacyDataMemberNamesAttribute: " + name);
var newProperty = (JsonProperty)clone.Invoke(property, new object[0]);
newProperty.Readable = false;
newProperty.PropertyName = name;
properties.Add(newProperty);
[LegacyDataMemberNames("alpha", "omega")]
public int A { get; set; }
public static class JsonExtensions
public static void RenameProperty(this JObject obj, string oldName, string newName)
throw new NullReferenceException();
var property = obj.Property(oldName);
property.Replace(new JProperty(newName, property.Value));
public static void Test()
var test = new TestObject { A = 42 };
var settings = new JsonSerializerSettings { ContractResolver = legacyResolver };
var json = JObject.FromObject(test, JsonSerializer.CreateDefault(settings));
Assert.IsTrue(!(json.SelectToken("alpha") != null || json.SelectToken("omega") != null));
json.RenameProperty("a", "alpha");
json.RenameProperty("alpha", "omega");
static IContractResolver legacyResolver = new LegacyPropertyResolver
private static void Test(TestObject test, JObject json)
var jsonString = json.ToString();
var settings = new JsonSerializerSettings { ContractResolver = legacyResolver };
var deserialized = JsonConvert.DeserializeObject<TestObject>(jsonString, settings);
Assert.AreEqual(test.A, deserialized.A);
Console.WriteLine("Successfully deserialized: " + json.ToString(Formatting.None));
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("{0} version: {1}", typeof(JsonSerializer).Assembly.GetName().Name, typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.Location.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];