Get differences in two JSON objects using newtonsoft
If you want to compare by newtonsoft
you can use bellow code
public static class ExtensionJson
{
public static IEnumerable<string> CompareJson(this JObject json, JObject json2, string path)
{
var result = new List<string>();
foreach (var property in json.Properties())
{
json2.TryGetValue(property.Name, out var itemTokenTwo);
if (itemTokenTwo == null)
{
result.Add($"{{ \"fieldName\": {path}{property.Path},\"targetValue\": {property.Value},\"sourceValue\": NULL }}");
continue;
}
if (property.Value.Type == JTokenType.Array && itemTokenTwo.Type == JTokenType.Array)
{
result.AddRange(JArray.Parse(property.Value.ToString()).CompareJson(JArray.Parse(itemTokenTwo.ToString()),
(!string.IsNullOrWhiteSpace(path) ? path + "." : default) + property.Path));
continue;
}
if (property.Value.Type == JTokenType.Object && itemTokenTwo.Type == JTokenType.Object)
{
result.AddRange(JObject.Parse(property.Value.ToString()).CompareJson(JObject.Parse(itemTokenTwo.ToString()), (!string.IsNullOrWhiteSpace(path) ? path + "." : default) + property.Path));
continue;
}
if (property.Value.Type != itemTokenTwo.Type)
{
result.Add($"{{ \"fieldName\": {path}{property.Path},\"targetValue\": {property.Value},\"sourceValue\": {itemTokenTwo} }}");
continue;
}
if (property.Value.ToString() != itemTokenTwo.Value<string>().ToString())
{
result.Add($"{{ \"fieldName\": {path}.{property.Path},\"targetValue\": {property.Value},\"sourceValue\": {itemTokenTwo} }}");
}
}
return result;
}
public static IEnumerable<string> CompareJson(this JArray json, JArray json2, string path)
{
var result = new List<string>();
foreach (var jToken in json)
{
var jToken2 = json2.SelectToken(jToken.Path);
if (jToken2 == null)
{
result.Add($"{{ \"fieldName\": {path}{jToken.Path},\"targetValue\": {jToken},\"sourceValue\": NULL }}");
continue;
}
if (jToken is JObject && jToken2 is JObject)
{
result.AddRange(JObject.Parse(jToken.ToString())
.CompareJson(JObject.Parse(jToken2.ToString()), path + jToken.Path));
continue;
}
if (jToken is JArray && jToken2 is JArray)
{
result.AddRange(JArray.Parse(jToken.ToString()).CompareJson(JArray.Parse(jToken2.ToString()), path + jToken.Path));
continue;
}
if (jToken is JProperty jProperty && jToken2 is JProperty token2)
{
if (jProperty.Value != token2.Value)
{
result.Add($"{{ \"fieldName\": {path}{jProperty.Path},\"targetValue\": {jProperty.Value},\"sourceValue\": {jToken2} }}");
}
}
else if (jToken is JValue value1 && jToken2 is JValue value2)
{
if (!value1.Equals(value2))
{
result.Add(
$"{{ \"fieldName\": {path}{jToken.Path},\"targetValue\": {value1},\"sourceValue\": {value2} }}");
}
}
else if (jToken is JProperty property)
{
result.Add($"{{ \"fieldName\": {path}{property.Path},\"targetValue\": {property.Value},\"sourceValue\": {jToken2} }}");
}
else
{
result.Add($"{{ \"fieldName\": {path}{((JProperty)jToken2).Path},\"targetValue\": {((JProperty)jToken2).Value},\"sourceValue\": {jToken} }}");
}
}
return result;
}
}
Main:
var json1 = @"{'name': 'Kirk',
'age': 23,
'phone': [
123123123,
141414
],
'address': [
{
'address1': '123',
'address2': '124'
},
{
'address1': '123',
'address2': '144',
'additionalInfo': {
'pin': 123321,
'landmark': 'landmark1'
}
},
{
'address1': '1223',
'addressLine2': '1242'
}
]
}";
var json2 = @"{
'name': 'Shawn',
'age': 23,
'phone': [
7852698,
141414
],
'address': [
{
'address1': '333',
'address2': '567'
},
{
'address1': '123',
'address2': '1414',
'additionalInfo': {
'pin': 1236381,
'landmark': 'landmark3'
}
}
]
}";
JObject json1O = JObject.Parse(json1);
JObject json2O = JObject.Parse(json2);
var items = JObject.Parse(json1).CompareJson(JObject.Parse(json2), json1O.Path);
foreach (var property in items)
{
Console.WriteLine(property + "\n\n");
}
Why Controller.Json and Newtonsoft Json return different results?
Because Controller.Json
produces JsonResult
object, which contains additional parameters. The overview of those can be found here. Whereas Newtonsoft serializes the specified object to a JSON string.
Data wise (that you serialize), they do produce the same result.
If you want to append to those properties, it's the normal use of getters and setters on an object:
return new JsonResult(result)
{
StatusCode = 200
};
And this object should be returned from the controller instead of return StatusCode(200, Json(data));
It's also worth pointing out that Json
is an extension method (helper method) for the JsonResult. They both return the same thing, an instance of JsonResult
(which in turn inherits ActionResult
).
Calling Json
or JsonResult
is a matter of preference, you'll have to write less for Json
and won't have to declare instances of JsonResult
in your controller as it'll be done behind the scenes for you.
How to compare two Json objects using C#
I did a bit more digging and was able to find out why the OP's test code doesn't run as expected. I was able to fix it by installing and using the FluentAssertions.Json nuget package.
One important thing:
Be sure to include
using FluentAssertions.Json
otherwise false
positives may occur.
Test code is the following:
using FluentAssertions;
using FluentAssertions.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
[TestFixture]
public class JsonTests
{
[Test]
public void JsonObject_ShouldBeEqualAsExpected()
{
JToken expected = JToken.Parse(@"{ ""Name"": ""20181004164456"", ""objectId"": ""4ea9b00b-d601-44af-a990-3034af18fdb1%>"" }");
JToken actual = JToken.Parse(@"{ ""Name"": ""AAAAAAAAAAAA"", ""objectId"": ""4ea9b00b-d601-44af-a990-3034af18fdb1%>"" }");
actual.Should().BeEquivalentTo(expected);
}
}
Running the test:
Detect differences between two json files in c#
I recommend you use Weakly-Typed JSON Serialization and write a routine that uses JsonObject like this:
String JsonDifferenceReport(String objectName,
JsonObject first,
JsonObject second)
{
if(String.IsNullOrEmpty(objectName))
throw new ArgumentNullException("objectName");
if(null==first)
throw new ArgumentNullException("first");
if(null==second)
throw new ArgumentNullException("second");
List<String> allKeys = new List<String>();
foreach(String key in first.Keys)
if (!allKeys.Any(X => X.Equals(key))) allKeys.Add(key);
foreach(String key in second.Keys)
if (!allKeys.Any(X => X.Equals(key))) allKeys.Add(key);
String results = String.Empty;
foreach(String key in allKeys)
{
JsonValue v1 = first[key];
JsonValue v1 = second[key];
if (((null==v1) != (null==v2)) || !v1.Equals(v2))
{
if(String.IsNullOrEmpty(results))
{
results = "differences: {\n";
}
results += "\t" + objectName + ": {\n";
results += "\t\tfield: " + key + ",\n";
results += "\t\toldvalue: " + (null==v1)? "null" : v1.ToString() + ",\n";
results += "\t\tnewvalue: " + (null==v2)? "null" : v2.ToString() + "\n";
results += "\t}\n";
}
}
if(!String.IsNullOrEmpty(results))
{
results += "}\n";
}
return results;
}
Your choice whether to get reports recursively inside JsonValue
v1 and v2, instead of just using their string representation as I did here.
If you wanted to go recursive, it might change the above like this:
if ((null==v1) || (v1.JsonType == JsonType.JsonPrimitive)
|| (null==v2) || (v2.JsonType == JsonType.JsonPrimitive))
{
results += "\t\tfield: " + key + ",\n";
results += "\t\toldvalue: " + (null==v1) ? "null" : v1.ToString() + ",\n";
results += "\t\tnewvalue: " + (null==v2) ? "null" : v2.ToString() + "\n";
}
else
{
results + JsonDifferenceReport(key, v1, v2);
}
-Jesse
Related Topics
How to Programmatically Limit My Program's CPU Usage to Below 70%
Serializable Classes and Dynamic Proxies in Ef - How
Filter a List by Another List C#
A Pattern for Self-Cancelling and Restarting Task
C# - How to Make Two Forms Reference Each Other
Copying Free Hand Drawing from Panel in Visual Studio 2013
Open a Folder Using Process.Start
How to Create an Odbc Dsn Entry Using C#
Comboboxes Are Linked for Some Reason
Change Flow of Messages in Microsoft Bot Framework
Extract Thumbnail for Any File in Windows
Using Custom Fonts on a Label on Winforms
Windows.Forms.Panel 32767 Size Limit
Rotate a Graphics Bitmap at Its Center
How to Know What Image Format I Get from a Stream