Параметры PropertyNamingPolicy, PropertyNameCaseInsensitive и Encoder учитываются при сериализации и десериализации пар "ключ-значение"

JsonSerializer теперь учитывает параметры PropertyNamingPolicy и Encoder при сериализации имен свойств Key и Value экземпляра KeyValuePair<TKey,TValue>. Кроме того, JsonSerializer учитывает параметры PropertyNamingPolicy и PropertyNameCaseInsensitive при десериализации экземпляров KeyValuePair<TKey,TValue>.

Описание изменения

Сериализация

В версиях .NET Core 3.x и версиях пакета NuGet System.Text.Json с 4.6.0 по 4.7.2 свойства экземпляров KeyValuePair<TKey,TValue> всегда сериализуются точно как "ключ" и "значение", независимо от значений параметров JsonSerializerOptions.PropertyNamingPolicy и JsonSerializerOptions.Encoder. В следующем примере кода показано, что имена свойств Key и Valueне задаются в "верблюжьем" стиле, несмотря на то, что такое поведение предписывается действующей политикой именования свойств.

var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
KeyValuePair<int, int> kvp = KeyValuePair.Create(1, 1);
Console.WriteLine(JsonSerializer.Serialize(kvp, options));
// Expected: {"key":1,"value":1}
// Actual: {"Key":1,"Value":1}

Начиная с .NET 5 параметры PropertyNamingPolicy и Encoder учитываются при сериализации экземпляров KeyValuePair<TKey,TValue>. В следующем примере кода показано, что имена свойств Key и Value после сериализации задаются в "верблюжьем" стиле в соответствии с действующей политикой именования свойств.

var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
KeyValuePair<int, int> kvp = KeyValuePair.Create(1, 1);
Console.WriteLine(JsonSerializer.Serialize(kvp, options));
// {"key":1,"value":1}

Десериализация

В версиях .NET Core 3.x и версиях 4.7.x пакета NuGet System.Text.Json возникает исключение JsonException, если имена свойств JSON не задаются в точности как Key и Value, например, если они не начинаются с прописной буквы. Исключение создается, даже если действующая политика именования свойств явно разрешает это.

var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
string json = @"{""key"":1,""value"":1}";
// Throws JsonException.
JsonSerializer.Deserialize<KeyValuePair<int, int>>(json, options);

Начиная с .NET 5 параметры PropertyNamingPolicy и PropertyNameCaseInsensitive учитываются при десериализации с использованием JsonSerializer. Например, в следующем фрагменте кода показана успешная десериализация имен свойств Key и Value в нижнем регистре, поскольку это допускается действующей политикой именования свойств.

var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
string json = @"{""key"":1,""value"":1}";

KeyValuePair<int, int> kvp = JsonSerializer.Deserialize<KeyValuePair<int, int>>(json);
Console.WriteLine(kvp.Key); // 1
Console.WriteLine(kvp.Value); // 1

Чтобы обеспечить соответствие полезных данных, которые были сериализованы с использованием предыдущих версий, "ключ" и "значение" имеют особый регистр для сопоставления при десериализации. Несмотря на то, что Key имена свойств Value не регистрируются в соответствии с PropertyNamingPolicy параметром в следующем примере кода, они успешно десериализируются.

var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
string json = @"{""Key"":1,""Value"":1}";

KeyValuePair<int, int> kvp = JsonSerializer.Deserialize<KeyValuePair<int, int>>(json);
Console.WriteLine(kvp.Key); // 1
Console.WriteLine(kvp.Value); // 1

Представленные версии

5,0

Причина изменения

Получено большое количество отзывов клиентов о необходимости учитывать PropertyNamingPolicy. Для полноты также учитываются параметры PropertyNameCaseInsensitive и Encoder, благодаря чему экземпляры KeyValuePair<TKey,TValue> обрабатываются так же, как и любой другой традиционный объект среды CLR (POCO).

Если это изменение нарушает работу, можно использовать настраиваемый преобразователь, который реализует нужную семантику.

Затронутые API