Обработка переполнения JSON или использование JsonElement или JsonNode
В этой статье показано, как обрабатывать переполнение JSON с System.Text.Json помощью пространства имен. В нем также показано, как десериализация в JsonElement или JsonNodeв качестве альтернативы для других сценариев, где целевой тип может не идеально соответствовать всем десериализированным json.
Обработка переполнения JSON
При десериализации в JSON могут быть получены данные, которые не представлены свойствами целевого типа. Предположим у вас есть следующий целевой тип:
public class WeatherForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
Public Class WeatherForecast
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
End Class
А десериализируемым кодом JSON является:
{
"Date": "2019-08-01T00:00:00-07:00",
"temperatureCelsius": 25,
"Summary": "Hot",
"DatesAvailable": [
"2019-08-01T00:00:00-07:00",
"2019-08-02T00:00:00-07:00"
],
"SummaryWords": [
"Cool",
"Windy",
"Humid"
]
}
При десериализации кода JSON, показанного в указанном типе, свойства DatesAvailable
и SummaryWords
никуда не переходят и будут потеряны. Для записи дополнительных данных, таких как эти свойства, примените атрибут [JsonExtensionData] к свойству типа Dictionary<string,object>
или Dictionary<string,JsonElement>
:
public class WeatherForecastWithExtensionData
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
[JsonExtensionData]
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}
Public Class WeatherForecastWithExtensionData
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
<JsonExtensionData>
Public Property ExtensionData As Dictionary(Of String, Object)
End Class
В следующей таблице показан результат десериализации JSON, показанного ранее в этом примере. Дополнительные данные становятся парами ExtensionData
"ключ-значение" свойства:
Свойство | Значение | Примечания. |
---|---|---|
Date |
"8/1/2019 12:00:00 AM -07:00" |
|
TemperatureCelsius |
0 |
Несовпадение с учетом регистра (temperatureCelsius в коде JSON), поэтому свойство не задано. |
Summary |
"Hot" |
|
ExtensionData |
"temperatureCelsius": 25, "DatesAvailable": ["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"], "SummaryWords": ["Cool","Windy","Humid"] |
Так как дело не совпадает, temperatureCelsius это дополнительная пара и становится парой "ключ-значение" в словаре. Каждый дополнительный массив из JSON становится парой "ключ-значение" с массивом в качестве объекта значения. |
Когда целевой объект сериализуется, пары "ключ-значение" данных расширения становятся свойствами JSON точно так же, как они были во входящем коде JSON:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 0,
"Summary": "Hot",
"temperatureCelsius": 25,
"DatesAvailable": [
"2019-08-01T00:00:00-07:00",
"2019-08-02T00:00:00-07:00"
],
"SummaryWords": [
"Cool",
"Windy",
"Humid"
]
}
Обратите внимание, что имя свойства ExtensionData
не отображается в коде JSON. Такое поведение позволяет JSON выполнить круговой путь без потери дополнительных данных, которые в противном случае не будут десериализованы.
В следующем примере показано круговое путешествие из JSON в десериализированный объект и обратно в JSON:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace RoundtripExtensionData
{
public class WeatherForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
[JsonExtensionData]
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString =
@"{
""Date"": ""2019-08-01T00:00:00-07:00"",
""temperatureCelsius"": 25,
""Summary"": ""Hot"",
""SummaryField"": ""Hot"",
""DatesAvailable"": [
""2019-08-01T00:00:00-07:00"",
""2019-08-02T00:00:00-07:00""
],
""SummaryWords"": [
""Cool"",
""Windy"",
""Humid""
]
}";
WeatherForecast weatherForecast =
JsonSerializer.Deserialize<WeatherForecast>(jsonString)!;
var serializeOptions = new JsonSerializerOptions { WriteIndented = true };
jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);
Console.WriteLine($"JSON output:\n{jsonString}\n");
}
}
}
// output:
//JSON output:
//{
// "Date": "2019-08-01T00:00:00-07:00",
// "TemperatureCelsius": 0,
// "Summary": "Hot",
// "temperatureCelsius": 25,
// "SummaryField": "Hot",
// "DatesAvailable": [
// "2019-08-01T00:00:00-07:00",
// "2019-08-02T00:00:00-07:00"
// ],
// "SummaryWords": [
// "Cool",
// "Windy",
// "Humid"
// ]
//}
Десериализация в JsonElement или JsonNode
Если вы просто хотите быть гибким по поводу того, что JSON допустимо для определенного свойства, альтернатива — десериализация в JsonElement или JsonNode. Любое допустимое свойство JSON можно десериализировать в JsonElement
или JsonNode
. ВыберитеJsonElement
, чтобы создать неизменяемый объект или JsonNode
создать изменяемый объект.
В следующем примере показана круговая поездка из JSON и обратно в JSON для класса, включающего свойства типа JsonElement
и JsonNode
.
using System.Text.Json;
using System.Text.Json.Nodes;
namespace RoundtripJsonElementAndNode
{
public class WeatherForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
public JsonElement DatesAvailable { get; set; }
public JsonNode? SummaryWords { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString =
@"{
""Date"": ""2019-08-01T00:00:00-07:00"",
""TemperatureCelsius"": 25,
""Summary"": ""Hot"",
""DatesAvailable"": [
""2019-08-01T00:00:00-07:00"",
""2019-08-02T00:00:00-07:00""
],
""SummaryWords"": [
""Cool"",
""Windy"",
""Humid""
]
}";
WeatherForecast? weatherForecast =
JsonSerializer.Deserialize<WeatherForecast>(jsonString);
var serializeOptions = new JsonSerializerOptions { WriteIndented = true };
jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);
Console.WriteLine(jsonString);
}
}
}
// output:
//{
// "Date": "2019-08-01T00:00:00-07:00",
// "TemperatureCelsius": 25,
// "Summary": "Hot",
// "DatesAvailable": [
// "2019-08-01T00:00:00-07:00",
// "2019-08-02T00:00:00-07:00"
// ],
// "SummaryWords": [
// "Cool",
// "Windy",
// "Humid"
// ]
//}