Given I have two c# objects of the same type, I want to compare them to create a JsonPatchDocument.
I have a StyleDetail class defined like this:
public class StyleDetail { public string Id { get; set; } public string Code { get; set; } public string Name { get; set; } public decimal OriginalPrice { get; set; } public decimal Price { get; set; } public string Notes { get; set; } public string ImageUrl { get; set; } public bool Wishlist { get; set; } public List<string> Attributes { get; set; } public ColourList Colours { get; set; } public SizeList Sizes { get; set; } public ResultPage<Style> Related { get; set; } public ResultPage<Style> Similar { get; set; } public List<Promotion> Promotions { get; set; } public int StoreStock { get; set; } public StyleDetail() { Attributes = new List<string>(); Colours = new ColourList(); Sizes = new SizeList(); Promotions = new List<Promotion>(); } }
if I have two StyleDetail objects
StyleDetail styleNew = db.GetStyle(123); StyleDetail styleOld = db.GetStyle(456);
I now want to create a JsonPatchDocument so I can send the differences to my REST API... How to do this??
JsonPatchDocument patch = new JsonPatchDocument(); // Now I want to populate patch with the differences between styleNew and styleOld - how?
in javascript, there is a library to do this https://www.npmjs.com/package/rfc6902
Calculate diff between two objects:
rfc6902.createPatch({first: 'Chris'}, {first: 'Chris', last: 'Brown'});
[ { op: 'add', path: '/last', value: 'Brown' } ]
but I am looking for a c# implementation
To test the sample, run the app and send HTTP requests with the following settings: Body: Copy and paste one of the JSON patch document samples from the JSON project folder. JSON Patch documentation. Includes links to resources for creating JSON Patch documents. This article explains how to handle JSON Patch requests in an ASP.NET Core web API.
The preceding code requires the Microsoft.AspNetCore.Mvc.NewtonsoftJson package and the following using statements: Use the Newtonsoft.Json.JsonConvert.SerializeObject method to serialize a JsonPatchDocument. The PUT and PATCH methods are used to update an existing resource.
The path property indicates the element to update. The value property provides the new value. The changes made by applying a JSON Patch document to a resource are atomic. If any operation in the list fails, no operation in the list is applied. If path points to an array element: removes the element.
The ASP.NET Core implementation of JSON Patch is provided in the Microsoft.AspNetCore.JsonPatch NuGet package. The package is included in the Microsoft.AspnetCore.App metapackage. Is annotated with the HttpPatch attribute. Accepts a JsonPatchDocument<T>, typically with [FromBody]. Calls ApplyTo on the patch document to apply the changes.
Let's abuse the fact that your classes are serializable to JSON! Here's a first attempt at a patch creator that doesn't care about your actual object, only about the JSON representation of that object.
public static JsonPatchDocument CreatePatch(object originalObject, object modifiedObject) { var original = JObject.FromObject(originalObject); var modified = JObject.FromObject(modifiedObject); var patch = new JsonPatchDocument(); FillPatchForObject(original, modified, patch, "/"); return patch; } static void FillPatchForObject(JObject orig, JObject mod, JsonPatchDocument patch, string path) { var origNames = orig.Properties().Select(x => x.Name).ToArray(); var modNames = mod.Properties().Select(x => x.Name).ToArray(); // Names removed in modified foreach (var k in origNames.Except(modNames)) { var prop = orig.Property(k); patch.Remove(path + prop.Name); } // Names added in modified foreach (var k in modNames.Except(origNames)) { var prop = mod.Property(k); patch.Add(path + prop.Name, prop.Value); } // Present in both foreach (var k in origNames.Intersect(modNames)) { var origProp = orig.Property(k); var modProp = mod.Property(k); if (origProp.Value.Type != modProp.Value.Type) { patch.Replace(path + modProp.Name, modProp.Value); } else if (!string.Equals( origProp.Value.ToString(Newtonsoft.Json.Formatting.None), modProp.Value.ToString(Newtonsoft.Json.Formatting.None))) { if (origProp.Value.Type == JTokenType.Object) { // Recurse into objects FillPatchForObject(origProp.Value as JObject, modProp.Value as JObject, patch, path + modProp.Name +"/"); } else { // Replace values directly patch.Replace(path + modProp.Name, modProp.Value); } } } }
Usage:
var patch = CreatePatch( new { Unchanged = new[] { 1, 2, 3, 4, 5 }, Changed = "1", Removed = "1" }, new { Unchanged = new[] { 1, 2, 3, 4, 5 }, Changed = "2", Added = new { x = "1" } }); // Result of JsonConvert.SerializeObject(patch) [ { "path": "/Removed", "op": "remove" }, { "value": { "x": "1" }, "path": "/Added", "op": "add" }, { "value": "2", "path": "/Changed", "op": "replace" } ]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With