Skip to content
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

Custom converters for enum dictionary keys not working as expected #94452

Closed
mavaddat opened this issue Nov 7, 2023 · 3 comments
Closed

Custom converters for enum dictionary keys not working as expected #94452

mavaddat opened this issue Nov 7, 2023 · 3 comments

Comments

@mavaddat
Copy link

mavaddat commented Nov 7, 2023

Description

I'm encountering an issue when trying to deserialize a JSON object to a Dictionary<CsdbProgram, Dictionary<int, UowState>> using System.Text.Json. Here, CsdbProgram is an enum and UowState is a class. I'm using custom converters for both CsdbProgram and UowState.

The deserialization fails with the following error message:

System.NotSupportedException: The type 'MauiXmlSplitter.Models.CsdbContext+CsdbProgram' is not a supported dictionary key using converter of type 'MauiXmlSplitter.Models.CsdbProgramConverter'. Path: $.GXPROD | LineNumber: 1 | BytePositionInLine: 11.

This is surprising because, as of .NET 6, System.Text.Json is supposed to support custom converters for dictionary keys. This feature was added in response to issue #46520 and implemented in pull request #57302.

However, it seems that this feature might not be working as expected for enum dictionary keys. I would appreciate it if you could look into this issue.

Reproduction Steps

  1. Define an enum CsdbProgram and a class UowState.
  2. Create a custom converter for CsdbProgram and UowState.
  3. Try to deserialize a JSON object to a Dictionary<CsdbProgram, Dictionary<int, UowState>> using JsonSerializer.DeserializeAsync and the custom converters.

Expected behavior

The JSON object is successfully deserialized to a Dictionary<CsdbProgram, Dictionary<int, UowState>>.

Actual behavior

Deserialization fails with a NotSupportedException.

Regression?

None available.

Known Workarounds

First deserialize the JSON to a Dictionary<string, Dictionary<int, UowState>> and then change the dictionary to a Dictionary<CsdbProgram, Dictionary<int, UowState>> using ToDictionary:

await using var statesPerProgramStream = await FileSystem.OpenAppPackageFileAsync("StatesPerProgram.json").ConfigureAwait(false); 
// Pass the options to the DeserializeAsync method
var statesPerProgramStr = await JsonSerializer.DeserializeAsync<Dictionary<string, Dictionary<int, UowState>>>(statesPerProgramStream, options,token).ConfigureAwait(false);
Debug.Assert(statesPerProgramStr != null);
// Convert string keys to CsdbProgram enum keys
statesPerProgram = statesPerProgramStr.ToDictionary(
    item => Enum.Parse<CsdbProgram>(item.Key),
    item => item.Value
);

Configuration

Microsoft Windows 10.0.19045, OSDImageName is Windows 10 x64 21H2 v8.0.
The version of .NET I am using is .NET 8.0 (8.0.100-rc.2.23502.2).
The target frameworks I am using are net8.0-android, net8.0-ios, net8.0-maccatalyst, and net8.0-windows10.0.19041.0.
The supported OS platform versions are 14.2 for iOS, 14.0 for MacCatalyst, 24.0 for Android, 10.0.17763.0 for Windows, and 6.5 for Tizen.
The application title is Bombardier XML Splitter and the application ID is com.bombardier.mauixmlsplitter.
The project URL is https://github.com/Technical-Publications-Bombardier/BaXmlSplitter and the repository type is git.

Other information

No response

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Nov 7, 2023
@ghost
Copy link

ghost commented Nov 7, 2023

Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

I'm encountering an issue when trying to deserialize a JSON object to a Dictionary<CsdbProgram, Dictionary<int, UowState>> using System.Text.Json. Here, CsdbProgram is an enum and UowState is a class. I'm using custom converters for both CsdbProgram and UowState.

The deserialization fails with the following error message:

System.NotSupportedException: The type 'MauiXmlSplitter.Models.CsdbContext+CsdbProgram' is not a supported dictionary key using converter of type 'MauiXmlSplitter.Models.CsdbProgramConverter'. Path: $.GXPROD | LineNumber: 1 | BytePositionInLine: 11.

This is surprising because, as of .NET 6, System.Text.Json is supposed to support custom converters for dictionary keys. This feature was added in response to issue #46520 and implemented in pull request #57302.

However, it seems that this feature might not be working as expected for enum dictionary keys. I would appreciate it if you could look into this issue.

Reproduction Steps

  1. Define an enum CsdbProgram and a class UowState.
  2. Create a custom converter for CsdbProgram and UowState.
  3. Try to deserialize a JSON object to a Dictionary<CsdbProgram, Dictionary<int, UowState>> using JsonSerializer.DeserializeAsync and the custom converters.

Expected behavior

The JSON object is successfully deserialized to a Dictionary<CsdbProgram, Dictionary<int, UowState>>.

Actual behavior

Deserialization fails with a NotSupportedException.

Regression?

None available.

Known Workarounds

First deserialize the JSON to a Dictionary<string, Dictionary<int, UowState>> and then change the dictionary to a Dictionary<CsdbProgram, Dictionary<int, UowState>> using ToDictionary:

await using var statesPerProgramStream = await FileSystem.OpenAppPackageFileAsync("StatesPerProgram.json").ConfigureAwait(false); 
// Pass the options to the DeserializeAsync method
var statesPerProgramStr = await JsonSerializer.DeserializeAsync<Dictionary<string, Dictionary<int, UowState>>>(statesPerProgramStream, options,token).ConfigureAwait(false);
Debug.Assert(statesPerProgramStr != null);
// Convert string keys to CsdbProgram enum keys
statesPerProgram = statesPerProgramStr.ToDictionary(
    item => Enum.Parse<CsdbProgram>(item.Key),
    item => item.Value
);

Configuration

Microsoft Windows 10.0.19045, OSDImageName is Windows 10 x64 21H2 v8.0.
The version of .NET I am using is .NET 8.0 (8.0.100-rc.2.23502.2).
The target frameworks I am using are net8.0-android, net8.0-ios, net8.0-maccatalyst, and net8.0-windows10.0.19041.0.
The supported OS platform versions are 14.2 for iOS, 14.0 for MacCatalyst, 24.0 for Android, 10.0.17763.0 for Windows, and 6.5 for Tizen.
The application title is Bombardier XML Splitter and the application ID is com.bombardier.mauixmlsplitter.
The project URL is https://github.com/Technical-Publications-Bombardier/BaXmlSplitter and the repository type is git.

Other information

No response

Author: mavaddat
Assignees: -
Labels:

area-System.Text.Json

Milestone: -

@eiriktsarpalis
Copy link
Member

Duplicate of #93406. Dictionary key converters need to override the dedicated WriteAsPropertyName/ReadAsPropertyName methods. We recently merged #93553 that should hopefully provide better guidance as to this in the error message.

@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Nov 7, 2023
@mavaddat
Copy link
Author

mavaddat commented Nov 7, 2023

Dictionary key converters need to override the dedicated WriteAsPropertyName/ReadAsPropertyName methods.

Cool! This solved my issue. Thank you.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants