-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
JsonDictionaryConverter throws when keys begin with escaped '$' #112288
Comments
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis |
The JSON strings
Can you clarify? I see no difference whether this property is turned on or off. |
FWIW we have this API proposal specifically intended to address this issue. |
Assigning to @eiriktsarpalis for continued triage. |
@eiriktsarpalis The difference in behavior seems to be intentional. The error text specifically indicates that this exception is intended to be avoidable by escaping the metadata indicator character:
That the JSON specification treats these as equivalent strings is irrelevant. This is a breaking change that was not (and still is not) called out in the documentations with no current mitigation.
I'll admit I did not try this, but based on the code I thought it would skip the key/value pair. However, it just moves the exception into This undocumented change in behavior has led to crashes in an application that I manage after migrating to dotnet 9. Whether you categorize it as a bug or bug fix, the dotnet foundation has a long-standing practice of disclosing such breaking changes. |
EDIT: Source generation for I still maintain that regardless of whether this change was addressing a bug in previous versions this constitutes a breaking change by any reasonable standard. Bugs (and fixes) happen, but informing developers is important for a framework as widely used as dotnet. |
.NET Core/modern .NET does not guarantee bugward compatibility. The breaking changes that we do document concern departures from the documented contract -- bugfixes as such do not meet the bar for breaking change documentation despite Hyrum's law holding true.
Every yearly release pushes thousands of bugfixes that impact observable behavior one way or another. Realistically, documenting everything as a breaking change wouldn't make our breaking change notes particularly helpful (since they would be practically indistinguishable from listing all PRs from github). |
Related to #107597. It should still be possible to turn it on using a bit of boilerplate: JsonSerializerOptions options = new(Context.Default.Options)
{
ReferenceHandler = ReferenceHandler.Preserve
};
JsonSerializer.Serialize(new Foo(), options);
[JsonSerializable(typeof(Foo))]
partial class Context : JsonSerializerContext; |
Respectfully, I disagree with your categorization. As previously mentioned this was not a bug but part of the documented behavior. At the risk of repeating myself, the Exception text clearly points to this workaround as an accepted option. The exception text retains this recommendation even in dotnet 9. At a minimum this text is now unequivocally incorrect - escaping the metadata character is not a viable option for addressing the exception. Regardless of whether this particular change is ultimately added to the list of breaking changes this thread at least provides some documentation of the change, along with potential workarounds for anyone affected. Would you prefer I open a separate issue to report the inaccurate Exception text, or is this report adequate for your needs? |
Could you point me to the documented behavior? Thanks. |
Emphasis is mine. |
Thanks. On the basis of that exception message I would declare the change a regression and recommend that we backport the fix to .NET 9. |
I did a bit of further digging, so I have more context now. The lack of unescaping in the metadata reader has been the source of roundtripping bugs specifically in the case of polymorphism, which allows user-defined metadata properties. The following code prints 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; Even if escaping the dollar sign was originally documented as a workaround for bypassing validation:
With this I would like to revise the action plan for this issue as follows:
|
That sounds like a good compromise. Using a custom converter works for my purposes, there are probably other workarounds that I haven't considered. Thank you for looking into this - I appreciate the effort! |
Addressed by #44748. |
That PR doesn't seem related - do you mean #112355 ? |
Should have been dotnet/docs#44748. Correct issue number but wrong repo :-) |
Description
Deserializing JSON with preserved references throws an exception if any dictionary keys begin with an escaped '$' character.
Reproduction Steps
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
The text was updated successfully, but these errors were encountered: