using Newtonsoft.Json.Linq;
using System.Collections.Generic;
public class PropertyChange
public string Name { get; set; }
public string From { get; set; }
public string To { get; set; }
public PropertyChange(string name, object from, object to)
public static void Main()
var diff = new Differ().GetDiff("{\"id\":1, \"name\":\"name v1\", \"roles\":[\"payment\", \"trade\"]}", "{\"id\":1, \"name\":\"name v2\", \"roles\":[\"payment\"]}");
Console.WriteLine("{0} from {1} to {2}", x.Name, x.From, x.To);
public PropertyChange[] GetDiff(string json1, string json2)
var object1 = JObject.Parse(json1);
var object2 = JObject.Parse(json2);
return GetDiff(object1, object2).ToArray();
private List<PropertyChange> GetDiff(JObject source, JObject target)
List<PropertyChange> result = new List<PropertyChange>();
foreach (KeyValuePair<string, JToken> sourcePair in source)
if (sourcePair.Value.Type == JTokenType.Object)
if (target.GetValue(sourcePair.Key) == null)
result.Add(new PropertyChange(sourcePair.Key, sourcePair.Value, "NULL"));
else if (target.GetValue(sourcePair.Key).Type != JTokenType.Object)
result.Add(new PropertyChange(sourcePair.Key, sourcePair.Value, target.GetValue(sourcePair.Key)));
result.AddRange(GetDiff(sourcePair.Value.ToObject<JObject>(), target.GetValue(sourcePair.Key).ToObject<JObject>()));
JToken sourceValue = sourcePair.Value;
var targetValue = target.GetValue(sourcePair.Key);
result.Add(new PropertyChange(sourcePair.Key, sourcePair.Value, "NULL"));
else if (sourceValue.ToString() != targetValue.ToString())
result.Add(new PropertyChange(sourcePair.Key, sourcePair.Value, targetValue));
foreach (KeyValuePair<string, JToken> targetPair in target)
if (source.ContainsKey(targetPair.Key))
result.Add(new PropertyChange(targetPair.Key, "NULL", targetPair.Value));