From 7d562a1ac763762a9d315077c0222cd32f330361 Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Mon, 15 Sep 2025 17:23:14 +0100 Subject: [PATCH 1/4] Fix #800 Add some blockItemConverters so we can ignore the obsolete properties even when they change --- uSync.Core/Extensions/JsonTextExtensions.cs | 2 + uSync.Core/Json/JsonBlockItemConverters.cs | 74 +++++++++++++++++++++ uSync.Core/Json/XElementJsonConverter.cs | 3 + 3 files changed, 79 insertions(+) create mode 100644 uSync.Core/Json/JsonBlockItemConverters.cs diff --git a/uSync.Core/Extensions/JsonTextExtensions.cs b/uSync.Core/Extensions/JsonTextExtensions.cs index 8f8a04129..b67e1d01c 100644 --- a/uSync.Core/Extensions/JsonTextExtensions.cs +++ b/uSync.Core/Extensions/JsonTextExtensions.cs @@ -31,6 +31,8 @@ public static class JsonTextExtensions new JsonUdiRangeConverter(), new JsonBooleanConverter(), new JsonXElementConverter(), + new JsonBlockListLayoutItemConverter(), + new JsonBlockGridLayoutItemConverter() } }; diff --git a/uSync.Core/Json/JsonBlockItemConverters.cs b/uSync.Core/Json/JsonBlockItemConverters.cs new file mode 100644 index 000000000..052e18171 --- /dev/null +++ b/uSync.Core/Json/JsonBlockItemConverters.cs @@ -0,0 +1,74 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +using Umbraco.Cms.Core.Models.Blocks; +using Umbraco.Extensions; + +namespace uSync.Core.Json; + +/// +/// in v16 the BlockLayoutItem(s) have obsolete properties that are sometimes set and sometimes not +/// this leads to false positive's when looking for changes. +/// +/// these two custom converters write those properties out as null, so they never change. causing +/// the serialized json to be consistent. +/// + +public abstract class JsonBlockItemConverterBase : JsonConverter + where T : BlockLayoutItemBase, new() +{ + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + throw new JsonException("Invalid JSON expecting start object"); + + var item = new T(); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + return item; + + if (reader.TokenType != JsonTokenType.PropertyName) + throw new JsonException("Expecting property name"); + + var propertyName = reader.GetString(); + reader.Read(); + + switch (propertyName) + { + case "contentKey": + var contentKey = reader.GetString(); + if (contentKey != null && Guid.TryParse(contentKey, out var contentGuid)) + item.ContentKey = contentGuid; + break; + case "settingsKey": + var settingsKey = reader.GetString(); + if (settingsKey != null && Guid.TryParse(settingsKey, out var settingsGuid)) + item.SettingsKey = settingsGuid; + break; + default: + // we don't care about the obsolete properties here... + break; + } + } + + throw new JsonException("Unexpected end of JSON"); + } + + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + // we could just not write out the obsolete properties, but they will appear as null it + // lots of people's existing exports , so we can write them out as null to keep things consistent. + writer.WriteStartObject(); + writer.WriteString("contentKey", value.ContentKey.ToString() ?? "null"); + writer.WriteString("contentUdi", "null"); + writer.WriteString("settingsKey", value.SettingsKey.ToString() ?? "null"); + writer.WriteString("settingsUdi", "null"); + writer.WriteEndObject(); + } +} + +public class JsonBlockListLayoutItemConverter : JsonBlockItemConverterBase { } + +public class JsonBlockGridLayoutItemConverter : JsonBlockItemConverterBase { } diff --git a/uSync.Core/Json/XElementJsonConverter.cs b/uSync.Core/Json/XElementJsonConverter.cs index 22b2a392b..0ea3d8aac 100644 --- a/uSync.Core/Json/XElementJsonConverter.cs +++ b/uSync.Core/Json/XElementJsonConverter.cs @@ -2,6 +2,8 @@ using System.Text.Json.Serialization; using System.Xml.Linq; +using Umbraco.Cms.Core.Models.Blocks; + namespace uSync.Core.Json; public class JsonXElementConverter : JsonConverter @@ -16,3 +18,4 @@ public override void Write(Utf8JsonWriter writer, XElement value, JsonSerializer writer.WriteStringValue(value.ToString()); } } + From e54836a38188f27632e11e39105e1a4a0cfcffdb Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Mon, 15 Sep 2025 17:36:02 +0100 Subject: [PATCH 2/4] write proper null values. --- uSync.Core/Json/JsonBlockItemConverters.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/uSync.Core/Json/JsonBlockItemConverters.cs b/uSync.Core/Json/JsonBlockItemConverters.cs index 052e18171..9e3def2b6 100644 --- a/uSync.Core/Json/JsonBlockItemConverters.cs +++ b/uSync.Core/Json/JsonBlockItemConverters.cs @@ -61,10 +61,15 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions // we could just not write out the obsolete properties, but they will appear as null it // lots of people's existing exports , so we can write them out as null to keep things consistent. writer.WriteStartObject(); - writer.WriteString("contentKey", value.ContentKey.ToString() ?? "null"); - writer.WriteString("contentUdi", "null"); - writer.WriteString("settingsKey", value.SettingsKey.ToString() ?? "null"); - writer.WriteString("settingsUdi", "null"); + writer.WriteString("contentKey", value.SettingsKey.ToString()); + writer.WriteNull("contentUdi"); + + if (value.SettingsKey.HasValue && value.SettingsKey != Guid.Empty) + writer.WriteString("settingsKey", value.SettingsKey.ToString()); + else + writer.WriteNull("settingsKey"); + + writer.WriteNull("settingsUdi"); writer.WriteEndObject(); } } From 065b85231ce18706278ac4777049090eae03d2de Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Mon, 15 Sep 2025 17:36:45 +0100 Subject: [PATCH 3/4] clean usings. --- uSync.Core/Json/JsonBlockItemConverters.cs | 1 - uSync.Core/Json/XElementJsonConverter.cs | 2 -- 2 files changed, 3 deletions(-) diff --git a/uSync.Core/Json/JsonBlockItemConverters.cs b/uSync.Core/Json/JsonBlockItemConverters.cs index 9e3def2b6..fdd012898 100644 --- a/uSync.Core/Json/JsonBlockItemConverters.cs +++ b/uSync.Core/Json/JsonBlockItemConverters.cs @@ -2,7 +2,6 @@ using System.Text.Json.Serialization; using Umbraco.Cms.Core.Models.Blocks; -using Umbraco.Extensions; namespace uSync.Core.Json; diff --git a/uSync.Core/Json/XElementJsonConverter.cs b/uSync.Core/Json/XElementJsonConverter.cs index 0ea3d8aac..23959e33e 100644 --- a/uSync.Core/Json/XElementJsonConverter.cs +++ b/uSync.Core/Json/XElementJsonConverter.cs @@ -2,8 +2,6 @@ using System.Text.Json.Serialization; using System.Xml.Linq; -using Umbraco.Cms.Core.Models.Blocks; - namespace uSync.Core.Json; public class JsonXElementConverter : JsonConverter From 27fa82bc5a309340e2995bb1a02d7b827defe511 Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Mon, 15 Sep 2025 17:37:52 +0100 Subject: [PATCH 4/4] Update uSync.Core/Json/JsonBlockItemConverters.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- uSync.Core/Json/JsonBlockItemConverters.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uSync.Core/Json/JsonBlockItemConverters.cs b/uSync.Core/Json/JsonBlockItemConverters.cs index fdd012898..529b65d87 100644 --- a/uSync.Core/Json/JsonBlockItemConverters.cs +++ b/uSync.Core/Json/JsonBlockItemConverters.cs @@ -60,7 +60,7 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions // we could just not write out the obsolete properties, but they will appear as null it // lots of people's existing exports , so we can write them out as null to keep things consistent. writer.WriteStartObject(); - writer.WriteString("contentKey", value.SettingsKey.ToString()); + writer.WriteString("contentKey", value.ContentKey.ToString()); writer.WriteNull("contentUdi"); if (value.SettingsKey.HasValue && value.SettingsKey != Guid.Empty)