Skip to content

[Breaking change]: System.Text.Json now validates property names conflicting with metadata properties #49879

@eiriktsarpalis

Description

@eiriktsarpalis

Description

Under certain contexts (polymorphism, reference preservation) System.Text.Json reserves specific property names that it uses to emit metadata over the wire: $type, $id, $ref, etc. It does so however without performing any validation on whether these property names conflict with user-defined contracts. In such situations, STJ would emit duplicate properties and produce JSON that is ambiguous or fails to roundtrip. Starting with .NET 10, STJ enables validation preventing such configurations, giving early warning to users.

Version

.NET 10

Previous behavior

The following code:

using System.Text.Json;
using System.Text.Json.Serialization;

string json = JsonSerializer.Serialize<Animal>(new Dog());
Console.WriteLine(json); // {"Type":"dog","Type":"Dog"}
JsonSerializer.Deserialize<Animal>(json); // JsonException: Deserialized object contains a duplicate 'Type' metadata property. 

[JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")]
[JsonDerivedType(typeof(Dog), "dog")]
public abstract class Animal
{
    public abstract string Type { get; }
}

public class Dog : Animal
{
    public override string Type => "Dog";
}

Will produce an invalid JSON object and fail to deserialize with a deserialization exception

New behavior

Starting with .NET 10 any attempt to serialize that same type will result in an early validation error:

InvalidOperationException: The type 'Dog' contains property 'Type' that conflicts with an existing metadata property name. Consider either renaming it or ignoring it with JsonIgnoreAttribute

Type of breaking change

  • Binary incompatible: Existing binaries might encounter a breaking change in behavior, such as failure to load or execute, and if so, require recompilation.
  • Source incompatible: When recompiled using the new SDK or component or to target the new runtime, existing source code might require source changes to compile successfully.
  • Behavioral change: Existing binaries might behave differently at run time.

Reason for change

Provides early prevention of invalid serialization contracts. See the original issue of [STJ] Disallow property names that conflict with metadata property names (dotnet/runtime#106390) and the pull request to Disallow types with property names conflicting with metadata. (dotnet/runtime#106460) for more information.

Recommended action

Users should avoid using property names that conflict with STJ specific metadata. If absolutely necessary to keep such a property around, a JsonIgnore annotation should be applied on the conflicting property.

Feature area

Serialization

Affected APIs

No response


Associated WorkItem - 508906

Metadata

Metadata

Labels

📌 seQUESTeredIdentifies that an issue has been imported into Quest.breaking-changeIndicates a .NET Core breaking change

Type

No type

Projects

Status

✅ Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions