Como lidar com JSON de estouro ou usar JsonElement ou JsonNode
Este artigo mostra como lidar com JSON de estouro com o System.Text.Json namespace. Ele também mostra como desserializar em JsonElement ou JsonNode, como uma alternativa para outros cenários onde o tipo de destino pode não corresponder perfeitamente a todo o JSON que está sendo desserializado.
Manipular JSON de estouro
Durante a desserialização, você pode receber dados no JSON que não são representados por propriedades do tipo de destino. Por exemplo, suponha que seu tipo de destino seja este:
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
E o JSON a ser desserializado é o seguinte:
{
"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"
]
}
Se você desserializar o JSON mostrado no tipo mostrado, as DatesAvailable
propriedades e SummaryWords
não terão para onde ir e serão perdidas. Para capturar dados extras, como essas propriedades, aplique o atributo [JsonExtensionData] a uma propriedade do tipo Dictionary<string,object>
ou 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
A tabela a seguir mostra o resultado da desserialização do JSON mostrado anteriormente neste tipo de exemplo. Os dados extras tornam-se pares chave-valor da ExtensionData
propriedade:
Property | valor | Notas |
---|---|---|
Date |
"8/1/2019 12:00:00 AM -07:00" |
|
TemperatureCelsius |
0 |
Incompatibilidade que diferencia maiúsculas de minúsculas (temperatureCelsius no JSON), para que a propriedade não seja definida. |
Summary |
"Hot" |
|
ExtensionData |
"temperatureCelsius": 25, "DatesAvailable": ["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"], "SummaryWords": ["Cool","Windy","Humid"] |
Uma vez que o caso não correspondeu, temperatureCelsius é um extra e torna-se um par chave-valor no dicionário. Cada matriz extra do JSON torna-se um par chave-valor, com uma matriz como o objeto value. |
Quando o objeto de destino é serializado, os pares de valores de chave de dados de extensão tornam-se propriedades JSON exatamente como estavam no JSON de entrada:
{
"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"
]
}
Observe que o nome da ExtensionData
propriedade não aparece no JSON. Esse comportamento permite que o JSON faça uma viagem de ida e volta sem perder nenhum dado extra que, de outra forma, não seria desserializado.
O exemplo a seguir mostra uma viagem de ida e volta de JSON para um objeto desserializado e de volta para 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"
// ]
//}
Desserializar em JsonElement ou JsonNode
Se você quiser apenas ser flexível sobre o JSON é aceitável para uma propriedade específica, uma alternativa é desserializar em JsonElement ou JsonNode. Qualquer propriedade JSON válida pode ser desserializada em JsonElement
ou JsonNode
. Escolha JsonElement
criar um objeto imutável ou JsonNode
criar um objeto mutável .
O exemplo a seguir mostra uma viagem de ida e volta de JSON e de volta para JSON para uma classe que inclui propriedades do tipo JsonElement
e 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"
// ]
//}