Fix double-encoding of non-string JSON values in nested blocks and add SingleBlock mapper#955
Merged
KevinJump merged 2 commits intoMay 13, 2026
Conversation
…d SingleBlock mapper
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a double-encoding issue where non-string JSON values (e.g. ["Orange"] from Umbraco.DropDown.Flexible) inside nested block properties were being re-serialized as JSON strings on import, corrupting the value. It also introduces a missing SingleBlockMapper so that properties inside Umbraco.SingleBlock editors are recursively processed in the same way as BlockList and BlockGrid.
Changes:
- In
SyncBlockMapperBase.GetImportProperty, when the original value was a non-string JSON type, convert the mapped string result back to aJsonNodeto preserve the original JSON shape. - Add a
IsNonStringJsonValuehelper that detectsJsonElement(anyValueKindexceptString/Undefined) as well asJsonArray/JsonObject. - Add a new
SingleBlockMapperregistered viaISyncMapperdiscovery, mirroringBlockListMapper/BlockGridMapperbut typed asSyncBlockMapperBase<SingleBlockValue>.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| uSync.Core/Mapping/SyncBlockMapperBase.cs | Adds JSON-type preservation on the import path to avoid double-encoding non-string values. |
| uSync.Core/Mapping/Mappers/SingleBlockMapper.cs | New mapper enabling recursive import/export processing of Umbraco.SingleBlock properties. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Owner
|
Hi Thanks for this, done some tests and it looks good 👍
|
Owner
|
In release v17.3.2 - https://www.nuget.org/packages/uSync/17.3.2 |
This was referenced May 18, 2026
alexsee
pushed a commit
to alexsee/umbraco-container
that referenced
this pull request
May 21, 2026
Updated [uSync](https://github.com/KevinJump/uSync) from 17.3.0 to 17.3.2. <details> <summary>Release notes</summary> _Sourced from [uSync's releases](https://github.com/KevinJump/uSync/releases)._ ## 17.3.2 This is a minor patch release of uSync for Umbraco v17, it contains updates to how some values are encoded inside blocks and proper support for SingleBlock elements. ## What's Changed * Fix double-encoding of non-string JSON values in nested blocks and add SingleBlock mapper by @koty10 in KevinJump/uSync#955 ## New Contributors * @koty10 made their first contribution in KevinJump/uSync#955 **Full Changelog**: KevinJump/uSync@v17.3.1...v17.3.2 ## 17.3.1 This is a Patch release for uSync for Umbraco v17.1. it contains fixes and updates for known issues.: the principle issue is uSync being to clever and trying to update the EditorUIAlias based on best guess when in some situations (#949) it should just leave it alone ## What's Changed * 👍 remove unused parameter on download, make it require admin at all times (not just tree access) by @KevinJump in KevinJump/uSync#948 * 👍 update build script so we genete uSync.Extend now too. by @KevinJump in KevinJump/uSync#951 * 🐛 Fixes: #949 - Property Editor UI alias values get overwritten on import by @KevinJump in KevinJump/uSync#950 **Full Changelog**: KevinJump/uSync@v17.3.0...v17.3.1 ### Installing ``` dotnet add package uSync --version 17.3.1 ``` ### Updating > [NOTE!] with the new centralized package management feature being using on v17.3+ umbraco projects you need to up date package versions using dotnet package update, dotnet add package won't do it. ``` dotnet package update uSync --version 17.3.1 ``` Commits viewable in [compare view](KevinJump/uSync@v17.3.0...v17.3.2). </details> Updated [uSync.Complete](https://jumoo.co.uk/uSync/complete) from 17.3.2 to 17.3.6. Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
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 characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix: Double-encoding of non-string JSON values inside block properties during import + missing SingleBlock mapper
Problem
When importing content that contains nested block structures (e.g. a BlockGrid with an area containing items that have SingleBlock properties with DropDown.Flexible fields), non-string JSON values get corrupted during import.
For example, a dropdown value
["Orange"](a JSON array) is correctly stored in the serialized XML, but after import it becomes the JSON string"[\"Orange\"]"(double-encoded). This causesJsonReaderExceptionerrors when rendering the page and shows invalid values in the backoffice.Root cause
SyncBlockMapperBase<T>.GetImportProperty()converts each block property value to a string viaGetStringValue(), sends it through the mapper collection, and assigns the result back toBlockPropertyValue.Value. For editors without a dedicated mapper (e.g.Umbraco.DropDown.Flexible), the raw string is returned and assigned back. When the parent block is re-serialized viaSerializeJsonString(), values that were originally JSON arrays/objects/numbers (but are now C# strings) get double-encoded.The export side (
GetExportProperty) already handles this correctly by converting the result back to aJsonNode:But the import side was missing this conversion.
Fix
SyncBlockMapperBase.GetImportProperty()— When the originalBlockPropertyValue.Valuewas a non-string JSON type (JsonElementwithValueKindof Array, Object, Number, etc.), the string result is now converted back to aJsonNodebefore being assigned back. This preserves the correct JSON type and prevents double-encoding. String-type values are left unchanged to avoid altering their type.New
SingleBlockMapper— Added a mapper forUmbraco.SingleBlock(analogous to existingBlockListMapperandBlockGridMapper). Without this, properties inside SingleBlock editors were never recursively processed during import — UDIs in MultiUrlPickers, media references, etc. inside SingleBlock were not mapped, and the entire SingleBlock value was subject to the double-encoding issue.Affected scenarios
Any property editor without a dedicated ISyncMapper that stores non-string JSON values (arrays, objects, numbers) inside any block type (BlockGrid, BlockList, SingleBlock). The most visible case is
Umbraco.DropDown.Flexiblewhich stores values as["SelectedValue"].How to reproduce
JsonReaderException