Skip to content

JsonDictionaryConverter throws when keys begin with escaped '$' #112288

Closed
@AE-ajones

Description

@AE-ajones

Description

Deserializing JSON with preserved references throws an exception if any dictionary keys begin with an escaped '$' character.

Reproduction Steps

using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
					
public record TestRecord{
	public Dictionary<string, string> TestDict {get; init;} = new();
}

public class Program
{
	public static void Main()
	{
		TestRecord test = new () {
			TestDict = new(){				
				["$break"] = "broken"
			}
		};
		
		TextEncoderSettings encoderSettings = new();
		encoderSettings.AllowRange(UnicodeRanges.BasicLatin);
		encoderSettings.ForbidCharacter('$');
		JsonSerializerOptions options = new(){ReferenceHandler = ReferenceHandler.Preserve, Encoder = JavaScriptEncoder.Create(encoderSettings)};
		
		string json = JsonSerializer.Serialize(test, options);
		TestRecord deserialized = JsonSerializer.Deserialize<TestRecord>(json, options);
	}
}

Expected behavior

The exception should only be thrown if a key begins with an unescaped '$' character.

Actual behavior

The repro steps below compile and execute in dotnet 8 without exception, in dotnet 9 the following exception is thrown:
System.Text.Json.JsonException: Properties that start with '$' are not allowed in types that support metadata. Either escape the character or disable reference preservation and polymorphic deserialization.

Regression?

This worked prior to dotnet 9. It is not a documented breaking change in https://learn.microsoft.com/en-us/dotnet/core/compatibility/9.0

Known Workarounds

Setting AllowOutOfOrderMetadataProperties to true will skip deserialization of the value. This is not a viable workaround for me.

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions