-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow custom converters for dictionary keys #46520
Comments
The larger feature here is allowing custom converters for dictionary keys. This was discussed as part of the design for allowing non-string dictionary keys in .NET 5 - #32676. The most likely route to achieving this is exposing these internal methods on runtime/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs Lines 542 to 546 in 3116c4d
cc @jozkee |
Moving this to future for now, but I'm ready to react if anyone needs this as a result of #50074. |
Exposing these virtual functions is what I exactly need. My converter is actually doing just that already and it was frustrating to find this out. Converting a type to string is pretty useful and I assume very common. Would love to see that on 6.0.0 🙏 |
From @martincostello in #53241. This feature should provide a reasonable mitigation for the breaking change described in that issue.
|
I would propose renaming the methods to something that better conveys their purpose, e.g. |
I would also argue that I would agree though, there is potential for a renaming. I would suggest any from the following:
|
@eiriktsarpalis @Fydar thanks. Read/WriteAsDictionary or similar better convey the intent of those APIs. Will update. |
namespace System.Text.Json.Serialization
{
public partial class JsonConverter<T>
{
protected virtual T ReadAsDictionaryKey(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options);
protected virtual void WriteAsDictionaryKey(Utf8JsonWriter writer, [DisallowNull] T value, JsonSerializerOptions options);
}
} |
It might be worth pointing out that not all IDictionary implementations guarantee that keys cannot be null. While all System.Collections implementations I know of do enforce this invariant, it is possible to have a dictionary implementation that does support null keys (for instance it could be relying on public class MyStringConverter : JsonConverter<string>
{
public override void WriteToPropertyName(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
writer.WritePropertyName(value ?? "LOL my dictionary has a null key");
}
}
On closer inspection I tend to agree with @layomia's remarks that materializing the string might have important performance ramifications. I temporarily considered the possibility of an API that converts to public class JsonConverter<T>
{
+ protected virtual T? ReadFromPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options);
+ protected virtual void WriteToPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options);
} |
Per offline discussion, if we can fix the regression for all key types (not just string) with minimal impact to the trimmed STJ.dll then that should be sufficient for V6 especially given the release schedule and priority. The new APIs to read\write dictionary keys as strings have low priority since there is no known feedback where these new APIs are needed and\or blocking, although there are valid scenarios for them. |
@steveharter I am following this issue here because it is really blocking for my company - we have some business logic rely on that. It messes with our code and there is no workaround atm. |
Hi @kirsanium, would your company be unblocked if #53241 were addressed, or does this specifically concern adding custom key converter support? |
@eiriktsarpalis, it's just about |
namespace System.Text.Json.Serialization
{
partial class JsonConverter<T>
{
protected virtual T? ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw null;
protected virtual void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { }
}
} |
Edited by @layomia.
Original post by @NN--- (click to view)
Description
JsonConverterAttribute is considered when used in a collection or as Dictionary value.
However, it is not considered when it is used as Dictionary key.
Please support JsonConvertAttribute on Dictionary keys.
Configuration
.NET 5.0.1
Regression?
No.
Other information
Today custom converters provided for types that appear in input graphs as dictionary keys (mostly primitives like
string
, numeric types, guids etc) cannot be used to handle dictionary keys. This manifests asNotSupportedException
being thrown by the serializer when a custom converter is used for these primitive types & and the types are serialized as dictionary keys. We should provide API to override theNSE
-throwing behavior and allow custom converters to handle dictionary keys.In .NET 5, the (de)serialization of dictionary keys was handled entirely by the serializer even when custom converters were provided for the dictionary key types. This behavior was broken earlier in the .NET 6 timeline as a known side effect of internal STJ infrastructure changes. Now, custom converters are also invoked for dictionary keys, but the mechanism to support them is internal and defaults to throwing
NotSupportedException
for all converters that are not internal in STJ & are supported as dictionary keys.API Proposal
This involves exposing the following internal virtual methods in the following form:
Notes
null
values as dictionary keys, so theHandleNull
property is not consulted when invoking theRead/WriteToPropertyName
methods. For the same reason, wrt to nullability, we have a signature ofT ReadFromPropertyName(...)
and notT? ReadFromPropertyName...
. Similarly we[DisallowNull]
for the inputT
in the corresponding write method.Read
andWrite
methods because the new functionality assumes that we are reading and writing strictly JSON property names, where the token type of the written value isJsonTokeType.PropertyName
. To avoid user-confusion about whether to check the currentreader.TokenType
when reading, and whether to write values usingwriter.WritePropertyName
, we introduce new methods where we can document the expected usage patterns.System.ComponentModel.TypeConverter
infrastructure).Read/Write
methods, e.g. passingJsonSerializerOptions
instances & the type to convert on deserialization.API usage
The text was updated successfully, but these errors were encountered: