System.Text.Json metadata reader now unescapes metadata property names

The System.Text.Json library has been updated to unescape metadata property names. This change affects how JSON documents are interpreted in the context of reference preservation, polymorphism, and metadata property validation.

Version introduced

.NET 9

Previous behavior

Previously, System.Text.Json didn't unescape metadata property names. This would lead to invalid property names being accepted, which could bypass metadata property validation.

For example, the following code would succeed in the first call but throw an exception in the second call:

JsonSerializerOptions options = new() { ReferenceHandler = ReferenceHandler.Preserve };
JsonSerializer.Deserialize<MyPoco>("""{"\u0024invalid" : 42 }""", options);
JsonSerializer.Deserialize<MyPoco>("""{"$invalid" : 42 }""", options);

record MyPoco;

The unescaping behavior could also cause polymorphism issues when roundtripping metadata properties whose names require escaping, as seen here:

string json = JsonSerializer.Serialize<Base>(new Derived());
Console.WriteLine(json); // {"categor\u00EDa":"derived"}
Console.WriteLine(JsonSerializer.Deserialize<Base>(json) is Derived); // False

[JsonPolymorphic(TypeDiscriminatorPropertyName = "categoría")]
[JsonDerivedType(typeof(Derived), "derived")]
public record Base;
public record Derived : Base;

New behavior

System.Text.Json now unescapes metadata property names. This new behavior means that the line Console.WriteLine(JsonSerializer.Deserialize<Base>(json) is Derived); from the polymorphic deserialization example now returns true, and that invalid property names correctly fail to deserialize with the following exception:

Unhandled exception. System.Text.Json.JsonException: Properties that start with '$' are not allowed in types that support metadata.

Type of breaking change

This change is a behavioral change.

Reason for change

The change improves correctness and reliability by ensuring that metadata property names are properly unescaped, preventing the bypass of metadata property validation. For more details, see the reported issue.

Avoid using escaping to bypass metadata property validation. Instead, pick property names that don't conflict with metadata properties.

Affected APIs