Fix duplicate key handling#10049
Merged
NikolaMilosavljevic merged 1 commit intodotnet:mainfrom Mar 25, 2026
Merged
Conversation
MiYanni
approved these changes
Mar 25, 2026
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.
Fixes #10025
Problem
After migrating from Newtonsoft.Json to System.Text.Json, loading template.json files with duplicate case-insensitive property keys (e.g.
"Empty"and"empty") throws anArgumentException:This affected MAUI templates (
maui-blazor,maui-blazor-solution) which intentionally had both"Empty"(PascalCase backward-compat alias) and"empty"(lowercase) symbol definitions.Root Cause
In
src/Shared/JExtensions.cs, theNodeOptionsfield was configured withPropertyNameCaseInsensitive = true:This caused
JsonObjectto use a case-insensitive internal dictionary. When any operation triggeredJsonObject.InitializeDictionary()(e.g. accessing.Count, iterating via.ToList()), it attempted to insert both"Empty"and"empty"into the same case-insensitive dictionary, throwing on the duplicate.This setting was redundant — all case-insensitive property lookups in the codebase already go through the
GetPropertyCaseInsensitive()helper method, which manually performs a case-insensitive fallback search.Fix
File changed:
src/Shared/JExtensions.csNodeOptionsfield entirely (it only existed to setPropertyNameCaseInsensitive = true)NodeOptionsinJsonNode.Parse()calls withnull(uses defaultJsonNodeOptions, which is case-sensitive)This means
JsonObjectnow stores properties with their original casing and uses a case-sensitive internal dictionary — which tolerates keys like"Empty"and"empty"coexisting. Case-insensitive lookups continue to work through the existingGetPropertyCaseInsensitive()helper.Test Added
File:
test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/GenericTests.csAdded
CanReadTemplateWithDuplicateCaseInsensitiveSymbolKeys— a regression test that verifies a template.json with symbols"Empty"and"empty"loads without throwing.