Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym artykule pokazano, jak obsługiwać przepełnienie kodu JSON przy użyciu System.Text.Json przestrzeni nazw. Pokazuje również, jak deserializować do JsonElement lub JsonNode jako alternatywę w innych scenariuszach, w których typ docelowy może nie być idealnie zgodny z całym deserializowanym kodem JSON.
Obsługa przepełnienia JSON
Podczas deserializacji można odbierać dane w formacie JSON, które nie są reprezentowane przez właściwości typu docelowego. Załóżmy na przykład, że twój typ docelowy to:
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
A kod JSON, który ma zostać zdeserializowany, jest następujący:
{
"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"
]
}
Jeśli zdeserializujesz pokazany kod JSON do pokazanego typu, właściwości DatesAvailable i SummaryWords nie mają gdzie trafić i zostaną utracone. Aby przechwycić dodatkowe dane, takie jak te właściwości, zastosuj atrybut [JsonExtensionData] do właściwości lub pola. Użyj jednej z następujących obsługiwanych deklaracji:
- Zadeklaruj składową danych rozszerzenia jako JsonObject.
- Zadeklaruj składnik extension-data jako
IDictionary<string, object>. - Zadeklaruj składową danych rozszerzeń jako
IDictionary<string, JsonElement>. - Zadeklaruj składową extension-data jako
IReadOnlyDictionary<string, object>w .NET 11 i nowszych wersjach. - Zadeklaruj składnik extension-data jako
IReadOnlyDictionary<string, JsonElement>w .NET 11 i nowszych wersjach.
W przypadku danych rozszerzenia słownika modyfikowalnego użyj dowolnego typu, który można przypisać do jednego z obsługiwanych IDictionary interfejsów, takich jak Dictionary<string, JsonElement>. Deklaracje tylko do odczytu muszą używać jednego z dokładnych IReadOnlyDictionary typów interfejsów wymienionych powyżej.
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
W przypadku składowej IReadOnlyDictionary extension-data platforma .NET 11 materializuje obiekt Dictionary<string, object> lub Dictionary<string, JsonElement>. Element członkowski musi być zapisywalny, ponieważ serializator wysiaduje nowy słownik z istniejących wartości i przypisuje go z powrotem. Jeśli przychodząca właściwość JSON powiela istniejący klucz, pierwszeństwo ma przychodząca wartość.
Poniższa tabela przedstawia wynik deserializacji pokazanego wcześniej kodu JSON do tego przykładowego typu. Dodatkowe dane stają się parami klucz-wartość we właściwości ExtensionData:
| Właściwości | Wartość | Uwagi |
|---|---|---|
Date |
"8/1/2019 12:00:00 AM -07:00" |
|
TemperatureCelsius |
0 |
Niezgodność związana z wielkością liter (temperatureCelsius w kodzie JSON), więc właściwość nie zostaje ustawiona. |
Summary |
"Hot" |
|
ExtensionData |
"temperatureCelsius": 25,"DatesAvailable": ["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"],"SummaryWords": ["Cool","Windy","Humid"] |
Ponieważ przypadek nie jest zgodny, temperatureCelsius jest dodatkową i staje się parą klucz-wartość w słowniku. Każda dodatkowa tablica z formatu JSON staje się parą klucz-wartość z tablicą jako obiekt wartości. |
Gdy obiekt docelowy jest serializowany, pary wartości klucza danych rozszerzenia stają się właściwościami JSON tak samo jak w przychodzącym formacie 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"
]
}
Zwróć uwagę, że ExtensionData nazwa właściwości nie jest wyświetlana w formacie JSON. To zachowanie pozwala kodowi JSON wykonać rundę bez utraty dodatkowych danych, które w przeciwnym razie nie zostaną zdeserializowane.
Od platformy .NET 11 serializacja spłaszcza dane rozszerzeń JsonObject do zawierającego je obiektu JSON. Właściwości JsonObject pojawiają się bezpośrednio w obiekcie nadrzędnym, a nie pod nazwą składowej extension-data.
Poniższy przykład pokazuje pełny cykl konwersji: od formatu JSON do zdeserializowanego obiektu i z powrotem do formatu 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"
// ]
//}
Deserializować do elementu JsonElement lub JsonNode
Jeśli chcesz być po prostu elastyczny co do tego, co JSON jest akceptowalne dla określonej właściwości, alternatywą jest deserializowanie do JsonElement lub JsonNode. Każda prawidłowa właściwość JSON może zostać zdeserializowana jako JsonElement lub JsonNode. Wybierz JsonElement , aby utworzyć niezmienny obiekt lub JsonNode utworzyć obiekt modyfikowalny .
Poniższy przykład przedstawia konwersję w obie strony z formatu JSON do formatu JSON dla klasy zawierającej właściwości typu JsonElement i 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"
// ]
//}