Last active
March 8, 2026 00:23
-
-
Save cajuncoding/bf78bdcf790782090d231590cbc2438f to your computer and use it in GitHub Desktop.
Revisions
-
cajuncoding revised this gist
Mar 7, 2026 . 1 changed file with 3 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,6 +14,9 @@ public static class SystemTextJsonMergeExtensions /// NOTE: JsonNodes are context aware and track their parent relationships therefore to merge the values both JsonNode objects /// specified are mutated. The Base is mutated with new data while the source is mutated to remove reverences to all /// fields so that they can be added to the base. /// This is unfortunately an unavoidable behavior of System.Text.Json. Therefore, I've opted to keep the mutating /// behavior in place to optimize for performance as the default behavior. And, it can be easily resolved by the caller /// simply calling `jsonNode.DeepClone()` prior to the merge -- providing full control to the caller. /// /// Source taken directly from the open-source Gist here: /// https://gist.github.com/cajuncoding/bf78bdcf790782090d231590cbc2438f -
cajuncoding revised this gist
Mar 4, 2026 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -81,6 +81,6 @@ public static JsonNode Merge(this JsonNode jsonBase, JsonNode jsonMerge, bool me /// <param name="options"></param> /// <returns></returns> public static JsonNode MergeDictionary<TKey, TValue>(this JsonNode jsonBase, IDictionary<TKey, TValue> dictionary, JsonSerializerOptions options = null, bool mergeIfAlreadyExists = true) => jsonBase.Merge(dictionary.ToJsonNode(options), mergeIfAlreadyExists); } } -
cajuncoding revised this gist
Jan 26, 2026 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -60,7 +60,7 @@ public static JsonNode Merge(this JsonNode jsonBase, JsonNode jsonMerge, bool me } default: throw new ArgumentException($"The JsonNode type [{jsonBase.GetType().Name}] is incompatible for merging with the target/base " + $"type [{jsonMerge.GetType().Name}]; merge requires the types to be the same."); } -
cajuncoding revised this gist
Jan 26, 2026 . 1 changed file with 8 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -23,7 +23,7 @@ public static class SystemTextJsonMergeExtensions /// <param name="jsonMerge"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> public static JsonNode Merge(this JsonNode jsonBase, JsonNode jsonMerge, bool mergeIfAlreadyExists = true) { if (jsonBase == null || jsonMerge == null) return jsonBase; @@ -39,6 +39,7 @@ public static JsonNode Merge(this JsonNode jsonBase, JsonNode jsonMerge) foreach (var prop in mergeNodesArray) { if(mergeIfAlreadyExists || !jsonBaseObj.ContainsKey(prop.Key)) jsonBaseObj[prop.Key] = jsonBaseObj[prop.Key] switch { JsonObject jsonBaseChildObj when prop.Value is JsonObject jsonMergeChildObj => jsonBaseChildObj.Merge(jsonMergeChildObj), @@ -54,7 +55,7 @@ public static JsonNode Merge(this JsonNode jsonBase, JsonNode jsonMerge) // so they can then be re-assigned to the target/base Json... var mergeNodesArray = jsonMergeArray.ToArray(); jsonMergeArray.Clear(); foreach (var mergeNode in mergeNodesArray) jsonBaseArray.Add(mergeNode); break; } default: @@ -68,14 +69,18 @@ public static JsonNode Merge(this JsonNode jsonBase, JsonNode jsonMerge) /// <summary> /// Merges the specified Dictionary of values into the base JsonNode for which this method is called. /// /// Source taken directly from the open-source Gist here: /// https://gist.github.com/cajuncoding/bf78bdcf790782090d231590cbc2438f /// /// </summary> /// <typeparam name="TKey"></typeparam> /// <typeparam name="TValue"></typeparam> /// <param name="jsonBase"></param> /// <param name="dictionary"></param> /// <param name="options"></param> /// <returns></returns> public static JsonNode MergeDictionary<TKey, TValue>(this JsonNode jsonBase, IDictionary<TKey, TValue> dictionary, JsonSerializerOptions options = null, bool mergeIfAlreadyExists = true) => jsonBase.Merge(JsonSerializer.SerializeToNode(dictionary, options)); } } -
cajuncoding revised this gist
Jul 12, 2024 . 1 changed file with 6 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -39,10 +39,12 @@ public static JsonNode Merge(this JsonNode jsonBase, JsonNode jsonMerge) foreach (var prop in mergeNodesArray) { jsonBaseObj[prop.Key] = jsonBaseObj[prop.Key] switch { JsonObject jsonBaseChildObj when prop.Value is JsonObject jsonMergeChildObj => jsonBaseChildObj.Merge(jsonMergeChildObj), JsonArray jsonBaseChildArray when prop.Value is JsonArray jsonMergeChildArray => jsonBaseChildArray.Merge(jsonMergeChildArray), _ => prop.Value }; } break; } -
cajuncoding revised this gist
Jun 3, 2024 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,9 +4,9 @@ using System.Text.Json; using System.Text.Json.Nodes; namespace CajunCoding { public static class SystemTextJsonMergeExtensions { /// <summary> /// Merges the specified Json Node into the base JsonNode for which this method is called. -
cajuncoding revised this gist
Jun 3, 2024 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,6 +14,10 @@ public static class SystemTextJsonExtensions /// NOTE: JsonNodes are context aware and track their parent relationships therefore to merge the values both JsonNode objects /// specified are mutated. The Base is mutated with new data while the source is mutated to remove reverences to all /// fields so that they can be added to the base. /// /// Source taken directly from the open-source Gist here: /// https://gist.github.com/cajuncoding/bf78bdcf790782090d231590cbc2438f /// /// </summary> /// <param name="jsonBase"></param> /// <param name="jsonMerge"></param> -
cajuncoding revised this gist
Jun 3, 2024 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,6 +10,7 @@ public static class SystemTextJsonExtensions { /// <summary> /// Merges the specified Json Node into the base JsonNode for which this method is called. /// It is null safe and can be easily used with null-check & null coalesce operators for fluent calls. /// NOTE: JsonNodes are context aware and track their parent relationships therefore to merge the values both JsonNode objects /// specified are mutated. The Base is mutated with new data while the source is mutated to remove reverences to all /// fields so that they can be added to the base. -
cajuncoding created this gist
Jun 3, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,74 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Text.Json.Nodes; namespace Maestro.Common.CustomJsonSerialization { public static class SystemTextJsonExtensions { /// <summary> /// Merges the specified Json Node into the base JsonNode for which this method is called. /// NOTE: JsonNodes are context aware and track their parent relationships therefore to merge the values both JsonNode objects /// specified are mutated. The Base is mutated with new data while the source is mutated to remove reverences to all /// fields so that they can be added to the base. /// </summary> /// <param name="jsonBase"></param> /// <param name="jsonMerge"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> public static JsonNode Merge(this JsonNode jsonBase, JsonNode jsonMerge) { if (jsonBase == null || jsonMerge == null) return jsonBase; switch (jsonBase) { case JsonObject jsonBaseObj when jsonMerge is JsonObject jsonMergeObj: { //NOTE: We must materialize the set (e.g. to an Array), and then clear the merge array so the node can then be // re-assigned to the target/base Json; clearing the Object seems to be the most efficient approach... var mergeNodesArray = jsonMergeObj.ToArray(); jsonMergeObj.Clear(); foreach (var prop in mergeNodesArray) { if (jsonBaseObj[prop.Key] is JsonObject jsonBaseChildObj && prop.Value is JsonObject jsonMergeChildObj) jsonBaseObj[prop.Key] = jsonBaseChildObj.Merge(jsonMergeChildObj); else jsonBaseObj[prop.Key] = prop.Value; } break; } case JsonArray jsonBaseArray when jsonMerge is JsonArray jsonMergeArray: { //NOTE: We must materialize the set (e.g. to an Array), and then clear the merge array, // so they can then be re-assigned to the target/base Json... var mergeNodesArray = jsonMergeArray.ToArray(); jsonMergeArray.Clear(); foreach(var mergeNode in mergeNodesArray) jsonBaseArray.Add(mergeNode); break; } default: throw new ArgumentException($"The JsonNode type [{jsonBase.GetType().Name}] is incompatible for merging with the target/base " + $"type [{jsonMerge.GetType().Name}]; merge requires the types to be the same."); } return jsonBase; } /// <summary> /// Merges the specified Dictionary of values into the base JsonNode for which this method is called. /// </summary> /// <typeparam name="TKey"></typeparam> /// <typeparam name="TValue"></typeparam> /// <param name="jsonBase"></param> /// <param name="dictionary"></param> /// <param name="options"></param> /// <returns></returns> public static JsonNode MergeDictionary<TKey, TValue>(this JsonNode jsonBase, IDictionary<TKey, TValue> dictionary, JsonSerializerOptions options = null) => jsonBase.Merge(JsonSerializer.SerializeToNode(dictionary, options)); } }