Eseguire la migrazione da Newtonsoft.Json a System.Text.Json
Questo articolo illustra come eseguire la migrazione da Newtonsoft.Json a System.Text.Json.
Lo spazio dei nomi System.Text.Json
fornisce funzionalità per la serializzazione e la deserializzazione da JavaScript Object Notation (JSON). La libreria System.Text.Json
è inclusa nel runtime per .NET Core 3.1 e versioni successive. Per altri framework di destinazione, installare il pacchetto NuGet System.Text.Json. Il pacchetto supporta:
- .NET Standard 2.0 e versioni successive
- .NET Framework 4.6.2 e versioni successive
- .NET Core 2.0, 2.1 e 2.2
Suggerimento
È possibile usare l'assistenza IA per eseguire la migrazione da Newtonsoft.Json
con GitHub Copilot.
System.Text.Json
si concentra principalmente su prestazioni, sicurezza e conformità agli standard. Presenta alcune differenze principali nel comportamento predefinito e non mira ad avere parità di funzionalità con Newtonsoft.Json
. Per alcuni scenari, System.Text.Json
attualmente non dispone di funzionalità predefinite, ma esistono soluzioni alternative consigliate. Per altri scenari, le soluzioni alternative non sono pratiche.
Il team System.Text.Json
sta investendo nell'aggiunta delle funzionalità più richieste. Se l'applicazione dipende da una funzionalità mancante, valutare la possibilità di segnalare un problema nel repository GitHub dotnet/runtime per scoprire se è possibile ricevere supporto per lo scenario in questione.
La maggior parte di questo articolo descrive come usare l'API JsonSerializer, ma include anche indicazioni su come usare i tipi JsonDocument (che rappresenta il Document Object Model o DOM), Utf8JsonReader e Utf8JsonWriter.
In Visual Basic non è possibile usare Utf8JsonReader, il che significa anche che non è possibile scrivere convertitori personalizzati. La maggior parte delle soluzioni alternative qui presentate richiede la scrittura di convertitori personalizzati. È possibile scrivere un convertitore personalizzato in C# e registrarlo in un progetto Visual Basic. Per altre informazioni, vedere Supporto di Visual Basic.
Tabella delle differenze
Nella tabella seguente sono elencate le caratteristiche Newtonsoft.Json
e gli equivalenti System.Text.Json
. Gli equivalenti rientrano nelle seguenti categorie:
- ✔️ Supportato dalla funzionalità predefinita. Ottenere un comportamento simile da
System.Text.Json
potrebbe richiedere l'uso di un attributo o di un'opzione globale. - ⚠️ Non supportato, ma è possibile una soluzione alternativa. Le soluzioni alternative sono i convertitori personalizzati che potrebbero non fornire la parità completa con la funzionalità
Newtonsoft.Json
. Per alcuni di questi, viene fornito come esempio il codice di esempio. Se si fa affidamento su queste funzionalitàNewtonsoft.Json
, la migrazione richiederà modifiche ai modelli a oggetti .NET o altre modifiche al codice. - ❌ Non supportato e la soluzione alternativa non è pratica né possibile. Se si fa affidamento su queste funzionalità
Newtonsoft.Json
, la migrazione non sarà possibile senza modifiche significative.
Funzionalità di Newtonsoft.Json | System.Text.Json equivalent |
---|---|
Deserializzazione senza distinzione tra maiuscole e minuscole per impostazione predefinita | ✔️ Impostazione globale PropertyNameCaseInsensitive |
Nomi delle proprietà camel-case | ✔️ Impostazione globale PropertyNamingPolicy |
Nomi delle proprietà snake-case | ✔️ Criteri di denominazione snake case |
Escape di caratteri minimo | ✔️ Escape dei caratteri rigidi, configurabile |
Impostazione globale NullValueHandling.Ignore |
✔️ Opzione globale DefaultIgnoreCondition |
Consentire commenti | ✔️ Impostazione globale ReadCommentHandling |
Consentire virgole finali | ✔️ Impostazione globale AllowTrailingCommas |
Registrazione del convertitore personalizzato | ✔️ L'ordine di precedenza è diverso |
Profondità massima predefinita 64, configurabile | ✔️ Profondità massima predefinita 64, configurabile |
Impostazione globale PreserveReferencesHandling |
✔️ Impostazione globale ReferenceHandling |
Serializzare o deserializzare numeri tra virgolette | ✔️ Impostazione globale NumberHandling, attributo [JsonNumberHandling] |
Deserializzare in classi e struct non modificabili | ✔️ JsonConstructor, record C# 9 |
Supporto per i campi | ✔️ Impostazione globale IncludeFields, attributo [JsonInclude] |
Impostazione globale DefaultValueHandling |
✔️ Opzione globale DefaultIgnoreCondition |
Impostazione NullValueHandling su [JsonProperty] |
✔️ Attributo JsonIgnore |
Impostazione DefaultValueHandling su [JsonProperty] |
✔️ Attributo JsonIgnore |
Deserializzare Dictionary con chiave non stringa |
✔️ Supportati |
Supporto per setter e getter di proprietà non pubblici | ✔️ Attributo JsonInclude |
Attributo [JsonConstructor] |
✔️ Attributo [JsonConstructor] |
Impostazione globale ReferenceLoopHandling |
✔️ Impostazione globale ReferenceHandling |
Callback | ✔️ Callback |
NaN, Infinity, -Infinity | ✔️ Supportati |
Impostazione Required sull'attributo [JsonProperty] |
✔️ Attributo [JsonRequired] e modificatore richiesto C# |
DefaultContractResolver per ignorare le proprietà |
✔️ Classe DefaultJsonTypeInfoResolver |
Serializzazione polimorfica | ✔️ Attributo [JsonDerivedType] |
Deserializzazione polimorfica | ✔️ Discriminante del tipo sull'attributo [JsonDerivedType] |
Deserializzare il valore di enumerazione stringa | ✔️ Deserializzare i valori di enumerazione stringa |
Impostazione globale MissingMemberHandling |
✔️ Gestire i membri mancanti |
Popolare le proprietà senza setter | ✔️ Popolare le proprietà senza setter |
Impostazione globale ObjectCreationHandling |
✔️ Riutilizzare anziché sostituire le proprietà |
Supporto per un'ampia gamma di tipi | ⚠️ Alcuni tipi richiedono convertitori personalizzati |
Deserializzare il tipo dedotto alle proprietà object |
⚠️ Non supportato, soluzione alternativa, esempio |
Deserializzare un valore letterale JSON null in tipi valore che non ammette i valori Null |
⚠️ Non supportato, soluzione alternativa, esempio |
DateTimeZoneHandling , impostazioni DateFormatString |
⚠️ Non supportato, soluzione alternativa, esempio |
Metodo JsonConvert.PopulateObject |
⚠️ Non supportato, soluzione alternativa |
Supporto per gli attributi System.Runtime.Serialization |
⚠️ Non supportato, soluzione alternativa, esempio |
JsonObjectAttribute |
⚠️ Non supportato, soluzione alternativa |
Consentire nomi di proprietà senza virgolette | ❌Non supportato dalla progettazione |
Consentire virgolette singole intorno ai valori stringa | ❌Non supportato dalla progettazione |
Consentire valori JSON non stringa per le proprietà stringa | ❌Non supportato dalla progettazione |
Impostazione globale TypeNameHandling.All |
❌Non supportato dalla progettazione |
Supporto per le query JsonPath |
❌Non supportato |
Limiti configurabili | ❌Non supportato |
Funzionalità di Newtonsoft.Json | System.Text.Json equivalent |
---|---|
Deserializzazione senza distinzione tra maiuscole e minuscole per impostazione predefinita | ✔️ Impostazione globale PropertyNameCaseInsensitive |
Nomi delle proprietà camel-case | ✔️ Impostazione globale PropertyNamingPolicy |
Escape di caratteri minimo | ✔️ Escape dei caratteri rigidi, configurabile |
Impostazione globale NullValueHandling.Ignore |
✔️ Opzione globale DefaultIgnoreCondition |
Consentire commenti | ✔️ Impostazione globale ReadCommentHandling |
Consentire virgole finali | ✔️ Impostazione globale AllowTrailingCommas |
Registrazione del convertitore personalizzato | ✔️ L'ordine di precedenza è diverso |
Profondità massima predefinita 64, configurabile | ✔️ Profondità massima predefinita 64, configurabile |
Impostazione globale PreserveReferencesHandling |
✔️ Impostazione globale ReferenceHandling |
Serializzare o deserializzare numeri tra virgolette | ✔️ Impostazione globale NumberHandling, attributo [JsonNumberHandling] |
Deserializzare in classi e struct non modificabili | ✔️ JsonConstructor, record C# 9 |
Supporto per i campi | ✔️ Impostazione globale IncludeFields, attributo [JsonInclude] |
Impostazione globale DefaultValueHandling |
✔️ Opzione globale DefaultIgnoreCondition |
Impostazione NullValueHandling su [JsonProperty] |
✔️ Attributo JsonIgnore |
Impostazione DefaultValueHandling su [JsonProperty] |
✔️ Attributo JsonIgnore |
Deserializzare Dictionary con chiave non stringa |
✔️ Supportati |
Supporto per setter e getter di proprietà non pubblici | ✔️ Attributo JsonInclude |
Attributo [JsonConstructor] |
✔️ Attributo [JsonConstructor] |
Impostazione globale ReferenceLoopHandling |
✔️ Impostazione globale ReferenceHandling |
Callback | ✔️ Callback |
NaN, Infinity, -Infinity | ✔️ Supportati |
Impostazione Required sull'attributo [JsonProperty] |
✔️ Attributo [JsonRequired] e modificatore richiesto C# |
DefaultContractResolver per ignorare le proprietà |
✔️ Classe DefaultJsonTypeInfoResolver |
Serializzazione polimorfica | ✔️ Attributo [JsonDerivedType] |
Deserializzazione polimorfica | ✔️ Discriminante del tipo sull'attributo [JsonDerivedType] |
Deserializzare il valore di enumerazione stringa | ✔️ Deserializzare i valori di enumerazione stringa |
Supporto per un'ampia gamma di tipi | ⚠️ Alcuni tipi richiedono convertitori personalizzati |
Deserializzare il tipo dedotto alle proprietà object |
⚠️ Non supportato, soluzione alternativa, esempio |
Deserializzare un valore letterale JSON null in tipi valore che non ammette i valori Null |
⚠️ Non supportato, soluzione alternativa, esempio |
DateTimeZoneHandling , impostazioni DateFormatString |
⚠️ Non supportato, soluzione alternativa, esempio |
Metodo JsonConvert.PopulateObject |
⚠️ Non supportato, soluzione alternativa |
Impostazione globale ObjectCreationHandling |
⚠️ Non supportato, soluzione alternativa |
Aggiungere a raccolte senza setter | ⚠️ Non supportato, soluzione alternativa |
Nomi delle proprietà snake-case | ⚠️ Non supportato, soluzione alternativa |
Supporto per gli attributi System.Runtime.Serialization |
⚠️ Non supportato, soluzione alternativa, esempio |
Impostazione globale MissingMemberHandling |
⚠️ Non supportato, soluzione alternativa, esempio |
JsonObjectAttribute |
⚠️ Non supportato, soluzione alternativa |
Consentire nomi di proprietà senza virgolette | ❌Non supportato dalla progettazione |
Consentire virgolette singole intorno ai valori stringa | ❌Non supportato dalla progettazione |
Consentire valori JSON non stringa per le proprietà stringa | ❌Non supportato dalla progettazione |
Impostazione globale TypeNameHandling.All |
❌Non supportato dalla progettazione |
Supporto per le query JsonPath |
❌Non supportato |
Limiti configurabili | ❌Non supportato |
Funzionalità di Newtonsoft.Json | System.Text.Json equivalent |
---|---|
Deserializzazione senza distinzione tra maiuscole e minuscole per impostazione predefinita | ✔️ Impostazione globale PropertyNameCaseInsensitive |
Nomi delle proprietà camel-case | ✔️ Impostazione globale PropertyNamingPolicy |
Escape di caratteri minimo | ✔️ Escape dei caratteri rigidi, configurabile |
Impostazione globale NullValueHandling.Ignore |
✔️ Opzione globale DefaultIgnoreCondition |
Consentire commenti | ✔️ Impostazione globale ReadCommentHandling |
Consentire virgole finali | ✔️ Impostazione globale AllowTrailingCommas |
Registrazione del convertitore personalizzato | ✔️ L'ordine di precedenza è diverso |
Profondità massima predefinita 64, configurabile | ✔️ Profondità massima predefinita 64, configurabile |
Impostazione globale PreserveReferencesHandling |
✔️ Impostazione globale ReferenceHandling |
Serializzare o deserializzare numeri tra virgolette | ✔️ Impostazione globale NumberHandling, attributo [JsonNumberHandling] |
Deserializzare in classi e struct non modificabili | ✔️ JsonConstructor, record C# 9 |
Supporto per i campi | ✔️ Impostazione globale IncludeFields, attributo [JsonInclude] |
Impostazione globale DefaultValueHandling |
✔️ Opzione globale DefaultIgnoreCondition |
Impostazione NullValueHandling su [JsonProperty] |
✔️ Attributo JsonIgnore |
Impostazione DefaultValueHandling su [JsonProperty] |
✔️ Attributo JsonIgnore |
Deserializzare Dictionary con chiave non stringa |
✔️ Supportati |
Supporto per setter e getter di proprietà non pubblici | ✔️ Attributo JsonInclude |
Attributo [JsonConstructor] |
✔️ Attributo [JsonConstructor] |
Impostazione globale ReferenceLoopHandling |
✔️ Impostazione globale ReferenceHandling |
Callback | ✔️ Callback |
NaN, Infinity, -Infinity | ✔️ Supportati |
Deserializzare il valore di enumerazione stringa | ✔️ Deserializzare i valori di enumerazione stringa |
Supporto per un'ampia gamma di tipi | ⚠️ Alcuni tipi richiedono convertitori personalizzati |
Serializzazione polimorfica | ⚠️ Non supportato, soluzione alternativa, esempio |
Deserializzazione polimorfica | ⚠️ Non supportato, soluzione alternativa, esempio |
Deserializzare il tipo dedotto alle proprietà object |
⚠️ Non supportato, soluzione alternativa, esempio |
Deserializzare un valore letterale JSON null in tipi valore che non ammette i valori Null |
⚠️ Non supportato, soluzione alternativa, esempio |
Impostazione Required sull'attributo [JsonProperty] |
⚠️ Non supportato, soluzione alternativa, esempio |
DefaultContractResolver per ignorare le proprietà |
⚠️ Non supportato, soluzione alternativa, esempio |
DateTimeZoneHandling , impostazioni DateFormatString |
⚠️ Non supportato, soluzione alternativa, esempio |
Metodo JsonConvert.PopulateObject |
⚠️ Non supportato, soluzione alternativa |
Impostazione globale ObjectCreationHandling |
⚠️ Non supportato, soluzione alternativa |
Aggiungere a raccolte senza setter | ⚠️ Non supportato, soluzione alternativa |
Nomi delle proprietà snake-case | ⚠️ Non supportato, soluzione alternativa |
JsonObjectAttribute |
⚠️ Non supportato, soluzione alternativa |
Supporto per gli attributi System.Runtime.Serialization |
❌Non supportato |
Impostazione globale MissingMemberHandling |
❌Non supportato |
Consentire nomi di proprietà senza virgolette | ❌Non supportato dalla progettazione |
Consentire virgolette singole intorno ai valori stringa | ❌Non supportato dalla progettazione |
Consentire valori JSON non stringa per le proprietà stringa | ❌Non supportato dalla progettazione |
Impostazione globale TypeNameHandling.All |
❌Non supportato dalla progettazione |
Supporto per le query JsonPath |
❌Non supportato |
Limiti configurabili | ❌Non supportato |
Questo non è un elenco completo delle funzionalità Newtonsoft.Json
. L'elenco include molti degli scenari richiesti nei problemi di GitHub o nei post di StackOverflow. Se si implementa una soluzione alternativa per uno degli scenari qui elencati che non dispone attualmente di codice di esempio e se si vuole condividere la soluzione, selezionare Questa pagina nella sezione Feedback nella parte inferiore di questa pagina. Ciò crea un problema nel repository GitHub di questa documentazione e lo elenca anche nella sezione Feedback in questa pagina.
Differenze nel comportamento predefinito
System.Text.Json è rigoroso per impostazione predefinita ed evita qualsiasi ipotesi o interpretazione per conto del chiamante, enfatizzando il comportamento deterministico. La libreria è progettata intenzionalmente in questo modo per garantire prestazioni e sicurezza. Newtonsoft.Json
è flessibile per impostazione predefinita. Questa differenza fondamentale nella progettazione è alla base di molte delle seguenti differenze specifiche nel comportamento predefinito.
Deserializzazione senza distinzione tra maiuscole e minuscole
Durante la deserializzazione, Newtonsoft.Json
esegue la corrispondenza del nome della proprietà senza distinzione tra maiuscole e minuscole per impostazione predefinita. L'impostazione predefinita System.Text.Json fa distinzione tra maiuscole e minuscole, il che offre prestazioni migliori perché esegue una corrispondenza esatta. Per ricevere informazioni su come eseguire la corrispondenza senza distinzione tra maiuscole e minuscole, vedere Corrispondenza di proprietà senza distinzione tra maiuscole e minuscole.
Se si usa indirettamente System.Text.Json
usando ASP.NET Core, non è necessario eseguire alcuna operazione per ottenere un comportamento come Newtonsoft.Json
. ASP.NET Core specifica le impostazioni per i nomi delle proprietà camel case e la corrispondenza senza distinzione tra maiuscole e minuscole quando usa System.Text.Json
.
ASP.NET Core abilita inoltre la deserializzazione dei numeri tra virgolette per impostazione predefinita.
Escape di caratteri minimo
Durante la serializzazione, Newtonsoft.Json
è relativamente permissivo nel lasciar passare i caratteri senza eliminarli. Ciò significa che non li sostituisce con \uxxxx
dove xxxx
è il punto di codice del carattere. Nei casi in cui esegue l'escape, lo fa emettendo un \
prima del carattere (ad esempio, "
diventa \"
). System.Text.Json esegue l'escape di più caratteri per impostazione predefinita per fornire protezioni approfondite contro scripting intersito (XSS) o attacchi di divulgazione di informazioni e lo fa usando la sequenza di sei caratteri. System.Text.Json
esegue l'escape di tutti i caratteri non ASCII per impostazione predefinita, pertanto non è necessario eseguire alcuna operazione se si usa StringEscapeHandling.EscapeNonAscii
in Newtonsoft.Json
. System.Text.Json
esegue anche l'escape dei caratteri con distinzione HTML, per impostazione predefinita. Per ricevere ulteriori informazioni su come eseguire l'override del comportamento predefinito System.Text.Json
, consultare l'articolo Come personalizzare la codifica dei caratteri.
Commenti
Durante la deserializzazione, Newtonsoft.Json
ignora i commenti nel codice JSON per impostazione predefinita. L'impostazione predefinita System.Text.Json prevede la generazione di eccezioni per i commenti perché la specifica RFC 8259 non li include. Per ricevere ulteriori informazioni su come consentire i commenti, vedere Consenti commenti e virgole finali.
Virgole finali
Durante la deserializzazione, Newtonsoft.Json
ignora le virgole finali per impostazione predefinita. Ignora anche più virgole finali, ad esempio [{"Color":"Red"},{"Color":"Green"},,]
. L'impostazione predefinita System.Text.Json prevede la generazione di eccezioni per le virgole finali perché la specifica RFC 8259 non li include. Per ricevere ulteriori informazioni su come consentire a System.Text.Json
di accettarli, vedere Consenti commenti e virgole finali. Non è possibile consentire più virgole finali.
Precedenza nella registrazione dei convertitori
La precedenza di registrazione Newtonsoft.Json
per i convertitori personalizzati è la seguente:
- Attributo sulla proprietà
- Attributo sul tipo
- Raccolta Convertitori
Questo ordine indica che un convertitore personalizzato nella raccolta Converters
viene sottoposto a override da un convertitore registrato applicando un attributo a livello di tipo. Entrambe le registrazioni vengono sottoposte a override da un attributo a livello di proprietà.
La precedenza di registrazione System.Text.Json per i convertitori personalizzati è la seguente:
- Attributo sulla proprietà
- Raccolta Converters
- Attributo sul tipo
La differenza è che un convertitore personalizzato nella raccolta Converters
esegue l'override di un attributo a livello di tipo. L'intenzione alla base di questo ordine di precedenza è fare in modo che le modifiche in fase di esecuzione eseguano l'override delle scelte in fase di progettazione. Non è possibile modificare la precedenza.
Per ottenere ulteriori informazioni sulla registrazione del convertitore personalizzato, vedere Registrare un convertitore personalizzato.
Profondità massima
La versione più recente di ha un limite massimo di Newtonsoft.Json
profondità di 64 per impostazione predefinita. System.Text.Json ha anche un limite predefinito di 64 ed è configurabile impostando JsonSerializerOptions.MaxDepth.
Se si usa indirettamente System.Text.Json
usando ASP.NET Core, il limite di profondità massimo predefinito è 32. Il valore predefinito è lo stesso dell'associazione di modelli ed è impostato nella classe JsonOptions.
Stringhe JSON (nomi di proprietà e valori stringa)
Durante la deserializzazione, Newtonsoft.Json
accetta nomi di proprietà racchiusi tra virgolette doppie, virgolette singole o senza virgolette. Accetta valori stringa racchiusi tra virgolette doppie o virgolette singole. Ad esempio, Newtonsoft.Json
accetta il codice JSON seguente:
{
"name1": "value",
'name2': "value",
name3: 'value'
}
System.Text.Json
accetta solo nomi di proprietà e valori stringa tra virgolette doppie perché tale formato è richiesto dalla specifica RFC 8259 ed è l'unico formato considerato JSON valido.
Un valore racchiuso tra virgolette singole restituisce un'eccezione JsonException con il messaggio seguente:
''' is an invalid start of a value.
Valori non stringa per le proprietà stringa
Newtonsoft.Json
accetta valori non stringa, ad esempio un numero o i valori letterali true
e false
, per la deserializzazione alla proprietà di tipo stringa. Ecco un esempio di JSON che Newtonsoft.Json
deserializza correttamente alla classe seguente:
{
"String1": 1,
"String2": true,
"String3": false
}
public class ExampleClass
{
public string String1 { get; set; }
public string String2 { get; set; }
public string String3 { get; set; }
}
System.Text.Json
non deserializza i valori non stringa in proprietà stringa. Un valore non stringa ricevuto per un campo stringa restituisce un'eccezione JsonException con il messaggio seguente:
The JSON value could not be converted to System.String.
Scenari con JsonSerializer
Alcuni degli scenari seguenti non sono supportati dalla funzionalità predefinita, ma sono possibili soluzioni alternative. Le soluzioni alternative sono convertitori personalizzati, che potrebbero non fornire la parità completa con le funzionalità Newtonsoft.Json
. Per alcuni di questi, viene fornito come esempio il codice di esempio. Se si fa affidamento su queste funzionalità Newtonsoft.Json
, la migrazione richiederà modifiche ai modelli a oggetti .NET o altre modifiche al codice.
Per alcuni degli scenari seguenti, le soluzioni alternative non sono pratiche né possibili. Se si fa affidamento su queste funzionalità Newtonsoft.Json
, la migrazione non sarà possibile senza modifiche significative.
Consentire o scrivere numeri tra virgolette
Newtonsoft.Json
può serializzare o deserializzare i numeri rappresentati da stringhe JSON (racchiuse tra virgolette). Ad esempio, può accettare {"DegreesCelsius":"23"}
anziché {"DegreesCelsius":23}
. Per abilitare questo comportamento in System.Text.Json, impostare JsonSerializerOptions.NumberHandling su WriteAsString o AllowReadingFromString oppure usare l'attributo [JsonNumberHandling].
Se si usa indirettamente System.Text.Json
usando ASP.NET Core, non è necessario eseguire alcuna operazione per ottenere un comportamento come Newtonsoft.Json
. ASP.NET Core specifica le impostazioni predefinite Web quando usa System.Text.Json
e le impostazioni predefinite Web consentono numeri tra virgolette.
Per ottenere ulteriori informazioni, vedere Consentire o scrivere numeri tra virgolette.
Specificare il costruttore da usare durante la deserializzazione
L'attributo Newtonsoft.Json
[JsonConstructor]
consente di specificare il costruttore da chiamare durante la deserializzazione a Plain Old CLR Object.
System.Text.Json
ha anche un attributo [JsonConstructor]. Per ottenere ulteriori informazioni, consultare l'articolo Usare tipi e proprietà non modificabili.
Ignorare in modo condizionale le proprietà
Newtonsoft.Json
offre diversi modi per ignorare in modo condizionale una proprietà sulla serializzazione o la deserializzazione:
DefaultContractResolver
consente di selezionare le proprietà da includere o ignorare in base a criteri arbitrari.- Le impostazioni
NullValueHandling
eDefaultValueHandling
suJsonSerializerSettings
consentono di specificare che tutte le proprietà con valore Null o con valore predefinito devono essere ignorate. - Le impostazioni
NullValueHandling
eDefaultValueHandling
sull'attributo[JsonProperty]
consentono di specificare le singole proprietà che devono essere ignorate se impostate su Null o sul valore predefinito.
System.Text.Json fornisce le modalità seguenti per ignorare le proprietà o i campi durante la serializzazione:
- L'attributo [JsonIgnore] in una proprietà fa sì che la proprietà venga omessa dal codice JSON durante la serializzazione.
- L'opzione globale IgnoreReadOnlyProperties consente di ignorare tutte le proprietà di sola lettura.
- Se si includono campi, l'opzione globale JsonSerializerOptions.IgnoreReadOnlyFields consente di ignorare tutti i campi di sola lettura.
- L'opzione globale
DefaultIgnoreCondition
consente di ignorare tutte le proprietà del tipo valore con valori predefiniti o di ignorare tutte le proprietà del tipo riferimento con valori Null.
Inoltre, in .NET 7 e versioni successive, è possibile personalizzare il contratto JSON per ignorare le proprietà in base a criteri arbitrari. Per ottenere ulteriori informazioni, vedere Contratti personalizzati.
Queste opzioni non consentono di ignorare le proprietà selezionate in base a criteri arbitrari valutati in fase di esecuzione.
Campi pubblici e non pubblici
Newtonsoft.Json
può serializzare e deserializzare i campi e le proprietà.
In System.Text.Json, usare l'impostazione globale JsonSerializerOptions.IncludeFields o l'attributo [JsonInclude] per includere campi pubblici durante la serializzazione o la deserializzazione. Per visualizzare alcuni esempi, consultare l'articolo Includere campi.
Mantenere i riferimenti agli oggetti e i cicli di handle
Per impostazione predefinita, Newtonsoft.Json
serializza gli oggetti per valore. Ad esempio, se un oggetto contiene due proprietà che contengono un riferimento allo stesso oggettoPerson
, i valori delle proprietà dell'oggetto Person
vengono duplicati nel codice JSON.
Newtonsoft.Json
ha un'impostazione PreserveReferencesHandling
su JsonSerializerSettings
che consente di serializzare in base al riferimento:
- I metadati dell'identificatore vengono aggiunti al codice JSON creato per il primo oggetto
Person
. - Il codice JSON creato per il secondo oggetto
Person
contiene un riferimento a tale identificatore anziché ai valori delle proprietà.
Newtonsoft.Json
include anche un'impostazione ReferenceLoopHandling
che consente di ignorare i riferimenti circolari anziché generare un'eccezione.
Per mantenere i riferimenti e gestire riferimenti circolari in System.Text.Json, impostare JsonSerializerOptions.ReferenceHandler su Preserve. L'impostazione ReferenceHandler.Preserve
equivale a PreserveReferencesHandling
= PreserveReferencesHandling.All
in Newtonsoft.Json
.
L'opzione ReferenceHandler.IgnoreCycles
ha un comportamento simile a Newtonsoft.JsonReferenceLoopHandling.Ignore
. Una differenza è che l'implementazione System.Text.Json sostituisce i cicli di riferimento con il token JSON null
anziché ignorare il riferimento all'oggetto. Per altre informazioni, vedere Ignorare i riferimenti circolari.
Analogamente a Newtonsoft.JsonReferenceResolver, la classe System.Text.Json.Serialization.ReferenceResolver definisce il comportamento che prevede il mantenimento dei riferimenti alla serializzazione e alla deserializzazione. Creare una classe derivata per specificare il comportamento personalizzato. Per un esempio, vedere GuidReferenceResolver.
Alcune funzionalità correlate Newtonsoft.Json
non sono supportate:
Per ottenere ulteriori informazioni, vedere Mantenere i riferimenti e gestire riferimenti circolari.
Dizionario con chiave non stringa
Sia Newtonsoft.Json
che System.Text.Json
supportano raccolte di tipo Dictionary<TKey, TValue>
. Tuttavia in System.Text.Json
, TKey
deve essere un tipo primitivo, non un tipo personalizzato. Per ottenere ulteriori informazioni, consultare la sezione Tipi di chiave supportati.
Attenzione
Deserializzazione in un oggetto Dictionary<TKey, TValue>
in cui TKey
viene tipizzato come qualsiasi elemento diverso da string
, potrebbe introdurre una vulnerabilità di sicurezza nell'applicazione che la utilizza. Per ottenere ulteriori informazioni, vedere dotnet/runtime#4761.
Tipi senza supporto predefinito
System.Text.Json non fornisce il supporto predefinito per i tipi seguenti:
- DataTable e i tipi correlati. Per ottenere ulteriori informazioni, vedere Tipi di raccolta supportati.
- ExpandoObject
- TimeZoneInfo
- BigInteger
- DBNull
- Type
- ValueTuple e i tipi generici associati
I convertitori personalizzati possono essere implementati per i tipi che non dispongono del supporto predefinito.
Serializzazione polimorfica
Newtonsoft.Json
esegue automaticamente la serializzazione polimorfica. A partire da .NET 7, System.Text.Json supporta la serializzazione polimorfica tramite l'attributo JsonDerivedTypeAttribute. Per altre informazioni, vedere Serializzare le proprietà delle classi derivate.
Deserializzazione polimorfica
Newtonsoft.Json
ha un'impostazione TypeNameHandling
che aggiunge metadati del nome di tipo al codice JSON durante la serializzazione. Usa i metadati durante la deserializzazione per eseguire la deserializzazione polimorfica. A partire da .NET 7, System.Text.Json si basa su informazioni del discriminatore del tipo per eseguire la deserializzazione polimorfica. Questi metadati vengono generati nel codice JSON e quindi usati durante la deserializzazione per determinare se deserializzare nel tipo di base o in un tipo derivato. Per altre informazioni, vedere Serializzare le proprietà delle classi derivate.
Per supportare la deserializzazione polimorfica nelle versioni precedenti di .NET, creare un convertitore come l'esempio illustrato in Come scrivere convertitori personalizzati.
Deserializzare i valori di enumerazione stringa
Per impostazione predefinita, System.Text.Json non supporta la deserializzazione dei valori di enumerazione delle stringhe, al contrario di Newtonsoft.Json
. Ad esempio, il codice seguente genera JsonException:
string json = "{ \"Text\": \"Hello\", \"Enum\": \"Two\" }";
var _ = JsonSerializer.Deserialize<MyObj>(json); // Throws exception.
class MyObj
{
public string Text { get; set; } = "";
public MyEnum Enum { get; set; }
}
enum MyEnum
{
One,
Two,
Three
}
Tuttavia, è possibile abilitare la deserializzazione dei valori di enumerazione stringa usando il convertitore JsonStringEnumConverter. Per ottenere ulteriori informazioni, vedi Enumerazioni come stringhe.
Deserializzazione delle proprietà dell'oggetto
Quando Newtonsoft.Json
deserializza in Object, esegue le seguenti operazioni:
- Deduce il tipo di valori primitivi nel payload JSON (diverso da
null
) e restituisce l'oggetto archiviatostring
,long
,double
,boolean
oDateTime
come oggetto boxed. I valori primitivi sono valori JSON singoli, ad esempio un numero JSON, una stringa,true
,false
, onull
. - Restituisce un oggetto
JObject
oJArray
per i valori complessi nel payload JSON. I valori complessi sono raccolte di coppie chiave-valore JSON tra parentesi graffe ({}
) o elenchi di valori racchiusi tra parentesi quadre ([]
). Le proprietà e i valori all'interno delle parentesi graffe o quadre possono avere proprietà o valori aggiuntivi. - Restituisce un riferimento Null quando il payload ha il valore letterale JSON
null
.
System.Text.Json archivia un oggetto boxed JsonElement
per i valori primitivi e complessi ogni volta che viene deserializzato in Object, ad esempio:
- Proprietà
object
. - Un valore del dizionario
object
. - Un valore della matrice
object
. - Una radice
object
.
Tuttavia, System.Text.Json
tratta null
allo stesso modo di Newtonsoft.Json
e restituisce un riferimento Null quando il payload contiene il valore letterale JSON null
.
Per implementare l'inferenza dei tipi per le proprietà object
, creare un convertitore come illustrato nell'esempio in Come scrivere convertitori personalizzati.
Deserializzare Null in un tipo che non ammette i valori Null
Nello scenario seguente,Newtonsoft.Json
non genera un'eccezione:
NullValueHandling
è impostato suIgnore
e- Durante la deserializzazione, il codice JSON contiene un valore Null per un tipo di valore che non ammette i valori Null.
Nello stesso scenario, System.Text.Json genera un'eccezione. L'impostazione di gestione dei valori Null corrispondente in System.Text.Json
è JsonSerializerOptions.IgnoreNullValues = true
.
Se si è proprietari del tipo di destinazione, la soluzione alternativa migliore consiste nel far sì che la proprietà in questione ammetta i valori Null (ad esempio, modificare int
in int?
).
Un'altra soluzione alternativa consiste nel creare un convertitore per il tipo. Nell'esempio seguente vengono gestisti i valori Null per i tipi DateTimeOffset
:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class DateTimeOffsetNullHandlingConverter : JsonConverter<DateTimeOffset>
{
public override DateTimeOffset Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
reader.TokenType == JsonTokenType.Null
? default
: reader.GetDateTimeOffset();
public override void Write(
Utf8JsonWriter writer,
DateTimeOffset dateTimeValue,
JsonSerializerOptions options) =>
writer.WriteStringValue(dateTimeValue);
}
}
Registrare questo convertitore personalizzato usando un attributo nella proprietà o aggiungendo il convertitore alla raccolta Converters.
Nota: il convertitore precedente gestisce i valori Null in modo diverso rispetto a Newtonsoft.Json
quello per i POCO che specificano i valori predefiniti. Si supponga, ad esempio, che il codice seguente rappresenti l'oggetto di destinazione:
public class WeatherForecastWithDefault
{
public WeatherForecastWithDefault()
{
Date = DateTimeOffset.Parse("2001-01-01");
Summary = "No summary";
}
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
}
Si supponga che il codice JSON seguente venga deserializzato usando il convertitore precedente:
{
"Date": null,
"TemperatureCelsius": 25,
"Summary": null
}
Dopo la deserializzazione, la proprietà Date
ha 1/1/0001 (default(DateTimeOffset)
), ciò significa che il valore impostato nel costruttore viene sovrascritto. Con gli stessi POCO e JSON, la deserializzazione Newtonsoft.Json
lascerebbe 1/1/2001 nella proprietà Date
.
Deserializzare in classi e struct non modificabili
Newtonsoft.Json
può deserializzare in classi e struct non modificabili perché può usare costruttori con parametri.
In System.Text.Json, usare l'attributo [JsonConstructor] per specificare l'uso di un costruttore con parametri. Anche i record in C# 9 non sono modificabili e sono supportati come destinazioni di deserializzazione. Per ottenere ulteriori informazioni, consultare l'articolo Usare tipi e proprietà non modificabili.
Proprietà obbligatorie
In Newtonsoft.Json
, specificare che una proprietà è obbligatoria impostando Required
sull'attributo [JsonProperty]
. Newtonsoft.Json
genera un'eccezione se non viene ricevuto alcun valore nel codice JSON per una proprietà contrassegnata come obbligatoria.
A partire da .NET 7, è possibile usare il modificatore C# required
o l'attributo JsonRequiredAttribute in una proprietà obbligatoria. System.Text.Json genera un'eccezione se il payload JSON non contiene un valore per la proprietà contrassegnata. Per altre informazioni, vedere Proprietà obbligatorie.
System.Text.Json non genera un'eccezione se non viene ricevuto alcun valore per una delle proprietà del tipo di destinazione. Ad esempio, se si dispone di una classe WeatherForecast
:
public class WeatherForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
Il codice JSON seguente viene deserializzato senza errori:
{
"TemperatureCelsius": 25,
"Summary": "Hot"
}
Per fare in modo che la deserializzazione abbia esito negativo se non è presente alcuna proprietà Date
nel codice JSON, scegliere una delle opzioni seguenti:
- Usare la versione .NET 7 o successiva del System.Text.Json pacchetto e aggiungere il modificatore
required
(disponibile a partire da C# 11) o l'attributo JsonRequiredAttribute alla proprietà. - Implementare un convertitore personalizzato.
- Implementare un callback
OnDeserialized
(.NET 6 e versioni successive).
Il codice del convertitore di esempio seguente genera un'eccezione se la proprietà Date
non è impostata dopo il completamento della deserializzazione:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class WeatherForecastRequiredPropertyConverter : JsonConverter<WeatherForecast>
{
public override WeatherForecast Read(
ref Utf8JsonReader reader,
Type type,
JsonSerializerOptions options)
{
// Don't pass in options when recursively calling Deserialize.
WeatherForecast forecast = JsonSerializer.Deserialize<WeatherForecast>(ref reader)!;
// Check for required fields set by values in JSON
return forecast!.Date == default
? throw new JsonException("Required property not received in the JSON")
: forecast;
}
public override void Write(
Utf8JsonWriter writer,
WeatherForecast forecast, JsonSerializerOptions options)
{
// Don't pass in options when recursively calling Serialize.
JsonSerializer.Serialize(writer, forecast);
}
}
}
Registrare questo convertitore personalizzato aggiungendo il convertitore alla raccolta JsonSerializerOptions.Converters.
Questo modello di chiamata ricorsiva al convertitore richiede di registrare il convertitore usando JsonSerializerOptions, non usando un attributo. Se si registra il convertitore usando un attributo, il convertitore personalizzato richiama sé stesso in modo ricorsivo. Il risultato è un ciclo infinito che termina con un'eccezione di overflow dello stack.
Quando si registra il convertitore usando l'oggetto opzioni, evitare un ciclo infinito non passando l'oggetto opzioni quando si chiama in modo ricorsivo Serialize o Deserialize. L'oggetto opzioni contiene la raccolta Converters. Se lo si passa a Serialize
o Deserialize
, il convertitore personalizzato chiama sé stesso, creando un ciclo infinito che genera un'eccezione di overflow dello stack. Se le opzioni predefinite non sono realizzabili, creare una nuova istanza delle opzioni con le impostazioni necessarie. Questo approccio sarà lento perché ogni nuova istanza memorizza nella cache in modo indipendente.
Esiste un modello alternativo che può usare la registrazione JsonConverterAttribute
nella classe da convertire. In questo approccio il codice del convertitore chiama Serialize
o Deserialize
su una classe che deriva dalla classe da convertire. Alla classe derivata non è applicato un oggetto JsonConverterAttribute
. Nell'esempio seguente di questa alternativa, è possibile constatare che:
WeatherForecastWithRequiredPropertyConverterAttribute
è la classe da deserializzare e a cui è applicatoJsonConverterAttribute
.WeatherForecastWithoutRequiredPropertyConverterAttribute
è la classe derivata che non ha l'attributo del convertitore.- Il codice nel convertitore chiama
Serialize
eDeserialize
suWeatherForecastWithoutRequiredPropertyConverterAttribute
per evitare un ciclo infinito. Questo approccio comporta un costo delle prestazioni per la serializzazione a causa di un'istanza aggiuntiva dell'oggetto e della copia dei valori delle proprietà.
Ecco i tipi di WeatherForecast*
:
[JsonConverter(typeof(WeatherForecastRequiredPropertyConverterForAttributeRegistration))]
public class WeatherForecastWithRequiredPropertyConverterAttribute
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
public class WeatherForecastWithoutRequiredPropertyConverterAttribute :
WeatherForecastWithRequiredPropertyConverterAttribute
{
}
Ed ecco il convertitore:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class WeatherForecastRequiredPropertyConverterForAttributeRegistration :
JsonConverter<WeatherForecastWithRequiredPropertyConverterAttribute>
{
public override WeatherForecastWithRequiredPropertyConverterAttribute Read(
ref Utf8JsonReader reader,
Type type,
JsonSerializerOptions options)
{
// OK to pass in options when recursively calling Deserialize.
WeatherForecastWithRequiredPropertyConverterAttribute forecast =
JsonSerializer.Deserialize<WeatherForecastWithoutRequiredPropertyConverterAttribute>(
ref reader,
options)!;
// Check for required fields set by values in JSON.
return forecast!.Date == default
? throw new JsonException("Required property not received in the JSON")
: forecast;
}
public override void Write(
Utf8JsonWriter writer,
WeatherForecastWithRequiredPropertyConverterAttribute forecast,
JsonSerializerOptions options)
{
var weatherForecastWithoutConverterAttributeOnClass =
new WeatherForecastWithoutRequiredPropertyConverterAttribute
{
Date = forecast.Date,
TemperatureCelsius = forecast.TemperatureCelsius,
Summary = forecast.Summary
};
// OK to pass in options when recursively calling Serialize.
JsonSerializer.Serialize(
writer,
weatherForecastWithoutConverterAttributeOnClass,
options);
}
}
}
Il convertitore di proprietà obbligatorio richiede una logica aggiuntiva se è necessario gestire attributi come [JsonIgnore] o opzioni diverse, come i codificatori personalizzati. Inoltre, il codice di esempio non gestisce le proprietà per le quali viene impostato un valore predefinito nel costruttore. E questo approccio non distingue tra gli scenari seguenti:
- Una proprietà non è presente nel codice JSON.
- Una proprietà per un tipo che non ammette valori Null è presente in JSON, ma il valore è l'impostazione predefinita per il tipo, ad esempio zero per un oggetto
int
. - Una proprietà per un tipo di valore che ammette i valori Null è presente nel codice JSON, ma il valore è Null.
Nota
Se si usa System.Text.Json da un controller ASP.NET Core, potrebbe essere possibile usare un attributo [Required]
sulle proprietà della classe del modello anziché implementare un convertitore System.Text.Json.
Specificare il formato della data
Newtonsoft.Json
offre diversi modi per controllare il modo in cui le proprietà dei tipi DateTime
e DateTimeOffset
vengono serializzate e deserializzate:
- L'impostazione
DateTimeZoneHandling
può essere usata per serializzare tutti i valoriDateTime
come date UTC. - L'impostazione
DateFormatString
e i convertitoriDateTime
possono essere usati per personalizzare il formato delle stringhe di data.
System.Text.Json supporta ISO 8601-1:2019, incluso il profilo RFC 3339. Questo formato è ampiamente adottato, non ambiguo e consente di effettuare round trip in modo preciso. Per usare qualsiasi altro formato, creare un convertitore personalizzato. Ad esempio, i convertitori seguenti serializzano e deserializzano JSON che usa il formato dell'epoca Unix con o senza una differenza di fuso orario (valori come /Date(1590863400000-0700)/
o /Date(1590863400000)/
):
sealed class UnixEpochDateTimeOffsetConverter : JsonConverter<DateTimeOffset>
{
static readonly DateTimeOffset s_epoch = new(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)([+-])(\\d{2})(\\d{2})\\)/$", RegexOptions.CultureInvariant);
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string formatted = reader.GetString()!;
Match match = s_regex.Match(formatted);
if (
!match.Success
|| !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime)
|| !int.TryParse(match.Groups[3].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int hours)
|| !int.TryParse(match.Groups[4].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int minutes))
{
throw new JsonException();
}
int sign = match.Groups[2].Value[0] == '+' ? 1 : -1;
TimeSpan utcOffset = new(hours * sign, minutes * sign, 0);
return s_epoch.AddMilliseconds(unixTime).ToOffset(utcOffset);
}
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options)
{
long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);
TimeSpan utcOffset = value.Offset;
string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/");
writer.WriteStringValue(formatted);
}
}
sealed class UnixEpochDateTimeConverter : JsonConverter<DateTime>
{
static readonly DateTime s_epoch = new(1970, 1, 1, 0, 0, 0);
static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)\\)/$", RegexOptions.CultureInvariant);
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string formatted = reader.GetString()!;
Match match = s_regex.Match(formatted);
if (
!match.Success
|| !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime))
{
throw new JsonException();
}
return s_epoch.AddMilliseconds(unixTime);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);
string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime})/");
writer.WriteStringValue(formatted);
}
}
Per altre informazioni, vedere Supporto di DateTime e DateTimeOffset in System.Text.Json.
Callback
Newtonsoft.Json
consente di eseguire un codice personalizzato in diversi punti del processo di serializzazione o deserializzazione:
- OnDeserializing (quando inizia a deserializzare un oggetto)
- OnDeserialized (al termine della deserializzazione di un oggetto)
- OnSerializing (quando inizia a deserializzare un oggetto)
- OnSerialized (al termine della deserializzazione di un oggetto)
System.Text.Json espone le stesse notifiche durante la serializzazione e la deserializzazione. Per usarle, implementare una o più delle interfacce seguenti dallo spazio dei nomi System.Text.Json.Serialization:
Di seguito si riporta un esempio che verifica la presenza di una proprietà Null e scrive messaggi all'inizio e alla fine della serializzazione e della deserializzazione:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Callbacks
{
public class WeatherForecast :
IJsonOnDeserializing, IJsonOnDeserialized,
IJsonOnSerializing, IJsonOnSerialized
{
public DateTime Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
void IJsonOnDeserializing.OnDeserializing() => Console.WriteLine("\nBegin deserializing");
void IJsonOnDeserialized.OnDeserialized()
{
Validate();
Console.WriteLine("Finished deserializing");
}
void IJsonOnSerializing.OnSerializing()
{
Console.WriteLine("Begin serializing");
Validate();
}
void IJsonOnSerialized.OnSerialized() => Console.WriteLine("Finished serializing");
private void Validate()
{
if (Summary is null)
{
Console.WriteLine("The 'Summary' property is 'null'.");
}
}
}
public class Program
{
public static void Main()
{
var weatherForecast = new WeatherForecast
{
Date = DateTime.Parse("2019-08-01"),
TemperatureCelsius = 25,
};
string jsonString = JsonSerializer.Serialize(weatherForecast);
Console.WriteLine(jsonString);
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString);
Console.WriteLine($"Date={weatherForecast?.Date}");
Console.WriteLine($"TemperatureCelsius={weatherForecast?.TemperatureCelsius}");
Console.WriteLine($"Summary={weatherForecast?.Summary}");
}
}
}
// output:
//Begin serializing
//The 'Summary' property is 'null'.
//Finished serializing
//{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":null}
//Begin deserializing
//The 'Summary' property is 'null'.
//Finished deserializing
//Date=8/1/2019 12:00:00 AM
//TemperatureCelsius = 25
//Summary=
Il codice OnDeserializing
non ha accesso alla nuova istanza POCO. Per modificare la nuova istanza POCO all'inizio della deserializzazione, inserire tale codice nel costruttore POCO.
Setter e getter di proprietà non pubblici
Newtonsoft.Json
può usare setter di proprietà privati e interni e getter tramite l'attributo JsonProperty
.
System.Text.Jsonsupporta setter di proprietà privati e interni e getter tramite l'attributo [JsonInclude]. Per consultare un codice di esempio, vedere la sezione Funzioni di accesso alle proprietà non pubbliche.
Popolare gli oggetti esistenti
Il metodo JsonConvert.PopulateObject
in Newtonsoft.Json
deserializza un documento JSON in un'istanza esistente di una classe, anziché creare una nuova istanza. System.Text.Json crea sempre una nuova istanza del tipo di destinazione usando il costruttore pubblico senza parametri predefinito. I convertitori personalizzati possono deserializzare in un'istanza esistente.
Riutilizzare anziché sostituire le proprietà
A partire da .NET 8, System.Text.Json supporta il riutilizzo delle proprietà inizializzate anziché la loro sostituzione. Esistono alcune differenze nel comportamento che è possibile leggere nella proposta dell'API.
Per altre informazioni, vedere Popolare le proprietà inizializzate.
L'impostazione ObjectCreationHandling
in Newtonsoft.Json
consente di specificare che gli oggetti nelle proprietà devono essere riutilizzati anziché sostituiti durante la deserializzazione. System.Text.Json sostituisce sempre gli oggetti nelle proprietà. I convertitori personalizzati possono fornire questa funzionalità oppure è possibile eseguire l'aggiornamento a .NET 8, che fornisce funzionalità di popolamento.
Popolare le proprietà senza setter
A partire da .NET 8, System.Text.Json supporta il popolamento delle proprietà, incluse quelle che non hanno un setter. Per altre informazioni, vedere Popolare le proprietà inizializzate.
Durante la deserializzazione, Newtonsoft.Json
aggiunge oggetti a una raccolta anche se la proprietà non dispone di setter. System.Text.Json ignora le proprietà che non hanno setter. I convertitori personalizzati possono fornire questa funzionalità oppure è possibile eseguire l'aggiornamento a .NET 8, che fornisce funzionalità di popolamento.
Criteri di denominazione snake case
System.Text.Json include un criterio di denominazione predefinito per snake case. Esistono tuttavia alcune differenze di comportamento con Newtonsoft.Json
per alcuni input. La tabella seguente illustra alcune di queste differenze durante la conversione dell'input usando i criteri JsonNamingPolicy.SnakeCaseLower.
Input | Risultato Newtonsoft.Json | Risultato System.Text.Json |
---|---|---|
"AB1" | "a_b1" | "ab1" |
"SHA512Managed" | "sh_a512_managed" | "sha512_managed" |
"abc123DEF456" | "abc123_de_f456" | "abc123_def456" |
"CASO KEBAB" | "keba_b-_case" | "kebab-case" |
L'unico criterio di denominazione delle proprietà predefinito in System.Text.Json è per camel case. Newtonsoft.Json
può convertire i nomi delle proprietà in snake case. Un criterio di denominazione personalizzato può fornire questa funzionalità o eseguire l'aggiornamento a .NET 8 o versioni successive, che include i criteri di denominazione di snake case predefiniti.
Attributi System.Runtime.Serialization
Attributi System.Runtime.Serialization come DataContractAttribute, DataMemberAttribute e IgnoreDataMemberAttribute consentono di definire un contratto di dati . Un contratto dati è un accordo formale tra un servizio e un client che descrive astrattamente i dati da scambiare. Il contratto di dati definisce con precisione le proprietà serializzate per lo scambio.
System.Text.Json non dispone del supporto predefinito per questi attributi. Tuttavia, a partire da .NET 7, è possibile usare un resolver di tipi personalizzato per aggiungere supporto. Per visualizzare un esempio, vedere ZCS.DataContractResolver.
Numeri ottali
Newtonsoft.Json
considera i numeri con uno zero iniziale come numeri ottali. System.Text.Json non consente zero iniziali perché non consentiti dalla specifica RFC 8259.
Gestire i membri mancanti
Se il codice JSON da deserializzare include proprietà mancanti nel tipo di destinazione, Newtonsoft.Json
può essere configurato per generare eccezioni. Per impostazione predefinita, System.Text.Json ignora le proprietà aggiuntive nel codice JSON, tranne quando si usa l'attributo [JsonExtensionData].
In .NET 8 e versioni successive è possibile impostare le preferenze per ignorare o disabilitare le proprietà JSON non mappate usando uno dei seguenti metodi:
- Applicare l'attributo JsonUnmappedMemberHandlingAttribute al tipo a cui si sta deserializzando.
- Per impostare le preferenze a livello globale, impostare la proprietà JsonSerializerOptions.UnmappedMemberHandling. In alternativa, per la generazione di origine, impostare la proprietà JsonSourceGenerationOptionsAttribute.UnmappedMemberHandling e applicare l'attributo alla classeJsonSerializerContext.
- Personalizzare la proprietà JsonTypeInfo.UnmappedMemberHandling.
JsonObjectAttribute
Newtonsoft.Json
dispone di un attributo JsonObjectAttribute
che può essere applicato a livello di tipo per controllare quali membri vengono serializzati, come vengono gestiti i valori null
e se sono obbligatori tutti i membri. System.Text.Json non dispone di un attributo equivalente che può essere applicato a un tipo. Per alcuni comportamenti, ad esempio la gestione dei valori null
, è possibile configurare lo stesso comportamento nel contesto globale JsonSerializerOptions o singolarmente in ogni proprietà.
Si consideri l'esempio seguente che usa Newtonsoft.Json.JsonObjectAttribute
per specificare che tutte le proprietà null
devono essere ignorate:
[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
public class Person { ... }
In System.Text.Json, è possibile impostare il comportamento per tutti i tipi e per tutte le proprietà :
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
string json = JsonSerializer.Serialize<Person>(person, options);
In alternativa, è possibile impostare il comportamento in ogni proprietà separatamente:
public class Person
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Name { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? Age { get; set; }
}
Si consideri quindi l'esempio seguente che usa Newtonsoft.Json.JsonObjectAttribute
per specificare che tutte le proprietà dei membri devono essere presenti nel codice JSON:
[JsonObject(ItemRequired = Required.Always)]
public class Person { ... }
È possibile ottenere lo stesso comportamento in System.Text.Json aggiungendo il modificatore C# required
o JsonRequiredAttribute a ogni proprietà. Per altre informazioni, vedere Proprietà obbligatorie.
public class Person
{
[JsonRequired]
public string? Name { get; set; }
public required int? Age { get; set; }
}
TraceWriter
Newtonsoft.Json
consente di eseguire il debug usando un oggetto TraceWriter
per visualizzare i log generati dalla serializzazione o dalla deserializzazione. System.Text.Json non esegue la registrazione.
JsonDocument e JsonElement confrontati rispetto a JToken (ad esempio JObject, JArray)
System.Text.Json.JsonDocument offre la possibilità di analizzare e compilare un DOM (Document Object Model) di sola lettura da payload JSON esistenti. DOM fornisce l'accesso casuale ai dati in un payload JSON. È possibile accedere agli elementi JSON che compongono il payload tramite il tipo JsonElement. Il JsonElement
tipo fornisce API per convertire il testo JSON in tipi .NET comuni. JsonDocument
espone una proprietà RootElement.
A partire da .NET 6, è possibile analizzare e compilare un DOM modificabile da payload JSON esistenti usando il tipo JsonNode e altri tipi nello spazio dei nomi System.Text.Json.Nodes. Per ottenere ulteriori informazioni, vedere Usare JsonNode
.
JsonDocument è IDisposable
JsonDocument
crea una vista in memoria dei dati in un buffer in pool. Pertanto, a differenza di JObject
o JArray
da Newtonsoft.Json
, il tipo JsonDocument
implementa IDisposable
e deve essere usato all'interno di un blocco using. Per altre informazioni, vedere JsonDocument è IDisposable.
JsonDocument è di sola lettura
Il DOM System.Text.Json non può aggiungere, rimuovere o modificare elementi JSON. È progettato in questo modo per le prestazioni e per ridurre le allocazioni per l'analisi delle dimensioni comuni del payload JSON (ovvero < 1 MB).
JsonElement è uno struct di unione
JsonDocument
espone RootElement
come proprietà di tipo JsonElement, che è un tipo di struct di unione che include qualsiasi elemento JSON. Newtonsoft.Json
usa tipi gerarchici dedicati come JObject
,JArray
, JToken
e così via. JsonElement
è ciò che è possibile cercare ed enumerare ed è possibile usare JsonElement
per materializzare gli elementi JSON in tipi .NET.
A partire da .NET 6, è possibile usare il tipo JsonNode e i tipi nello spazio dei nomi System.Text.Json.Nodes che corrispondono a JObject
,JArray
e JToken
. Per ottenere ulteriori informazioni, vedere Usare JsonNode
.
Come cercare elementi secondari in JsonDocument e JsonElement
Le ricerche di token JSON che usano JObject
o JArray
da Newtonsoft.Json
tendono a essere relativamente veloci perché sono ricerche in un dizionario. A confronto, le ricerche in JsonElement
richiedono una ricerca sequenziale delle proprietà e quindi sono relativamente lente (ad esempio quando si usa TryGetProperty
). System.Text.Json è progettato per ridurre al minimo il tempo di analisi iniziale anziché il tempo di ricerca. Per ottenere ulteriori informazioni, vedere Come cercare elementi secondari in JsonDocument e JsonElement.
Utf8JsonReader vs. JsonTextReader
System.Text.Json.Utf8JsonReader è un lettore forward-only a prestazioni elevate e allocazione ridotta per il testo JSON con codifica UTF-8, letto da un byte ReadOnlySpan<> o da un byte ReadOnlySequence<>. Utf8JsonReader
è un tipo di basso livello che può essere usato per creare parser e deserializzatori personalizzati.
Utf8JsonReader è uno struct di riferimento
JsonTextReader
in Newtonsoft.Json
è una classe. Il tipo Utf8JsonReader
è diverso poiché è uno struct di riferimento. Per ottenere ulteriori informazioni, vedere Limitazioni degli struct di riferimento per Utf8JsonReader.
Leggere i valori Null in tipi di valore che ammettono i valori Null
Newtonsoft.Json
fornisce API che restituiscono Nullable<T>, ad esempio ReadAsBoolean
, che gestisce un oggetto Null
TokenType
per l'utente restituendo un oggetto bool?
. Le API predefinite System.Text.Json
restituiscono solo tipi valore che non ammettono i valori Null. Per ottenere ulteriori informazioni, vedere Leggere i valori Null in tipi di valore che ammettono i valori Null.
Multi-target per la lettura di JSON
Se è necessario continuare a usare Newtonsoft.Json
per determinati framework di destinazione, è possibile usare più partizioni e avere due implementazioni. Tuttavia, questo non è semplice e richiederebbe alcuni #ifdefs
e la duplicazione di origine. Un modo per condividere il maggior numero possibile di codici consiste nel creare un wrapper ref struct
intorno a Utf8JsonReader e Newtonsoft.Json.JsonTextReader
. Questo wrapper unifica l'area di superficie pubblica isolando le differenze comportamentali. Ciò consente di isolare principalmente le modifiche alla costruzione del tipo, oltre a passare il nuovo tipo per riferimento. Questo è il modello seguito dalla libreria Microsoft.Extensions.DependencyModel :
Utf8JsonWriter vs. JsonTextWriter
System.Text.Json.Utf8JsonWriter è un modo ad alte prestazioni per scrivere testo JSON con codifica UTF-8 da tipi .NET comuni come String
, Int32
e DateTime
. Il writer è un tipo di basso livello che può essere usato per creare serializzatori personalizzati.
Scrivere valori non elaborati
Newtonsoft.Json
dispone di un metodo WriteRawValue
che scrive codice JSON non elaborato in cui è previsto un valore. System.Text.Json ha come equivalente diretto Utf8JsonWriter.WriteRawValue. Per ottenere ulteriori informazioni, vedere la sezioneScrivere codice JSON non elaborato.
Personalizzare il formato JSON
JsonTextWriter
include le impostazioni seguenti, per le quali Utf8JsonWriter non ha un equivalente:
- QuoteChar: specifica il carattere da usare per racchiudere i valori stringa.
Utf8JsonWriter
usa sempre le virgolette doppie. - QuoteName: specifica se racchiudere o meno i nomi delle proprietà tra virgolette.
Utf8JsonWriter
li racchiude sempre tra virgolette.
A partire da .NET 9, è possibile personalizzare il carattere di rientro e le dimensioni per Utf8JsonWriter utilizzando le opzioni esposte dallo struct JsonWriterOptions:
JsonTextWriter
include le impostazioni seguenti, per le quali Utf8JsonWriter
non ha un equivalente:
- Indentation: specifica il numero di caratteri per impostare un rientro.
Utf8JsonWriter
rientra sempre di 2 caratteri. - IndentChar: specifica il carattere da utilizzare per il rientro.
Utf8JsonWriter
usa sempre spazi vuoti. - QuoteChar: specifica il carattere da usare per racchiudere i valori stringa.
Utf8JsonWriter
usa sempre le virgolette doppie. - QuoteName: specifica se racchiudere o meno i nomi delle proprietà tra virgolette.
Utf8JsonWriter
li racchiude sempre tra virgolette.
Non esistono soluzioni alternative che consentono di personalizzare il codice JSON prodotto da Utf8JsonWriter
in questi modi.
Scrivere valori Timespan, Uri o char
JsonTextWriter
fornisce metodi WriteValue
per i valori TimeSpan, Uri e char. Utf8JsonWriter
non dispone di metodi equivalenti. Al contrario, formattare questi valori come stringhe (chiamando ad esempio ToString()
) e chiamare WriteStringValue.
Multi-destinazione per la scrittura di JSON
Se è necessario continuare a usare Newtonsoft.Json
per determinati framework di destinazione, è possibile usare più partizioni e avere due implementazioni. Tuttavia, questo non è semplice e richiederebbe alcuni #ifdefs
e la duplicazione di origine. Un modo per condividere il maggior numero possibile di codici consiste nel creare un wrapper Utf8JsonWriter intorno a Newtonsoft.Json.JsonTextWriter
. Questo wrapper unifica l'area di superficie pubblica isolando le differenze comportamentali. In questo modo è possibile isolare principalmente le modifiche alla costruzione del tipo. La libreria Microsoft.Extensions.DependencyModel segue:
TypeNameHandling.All non supportato
La decisione di escludere la funzionalità equivalente TypeNameHandling.All
da System.Text.Json
è stata intenzionale. Consentire a un payload JSON di specificare le proprie informazioni sul tipo è una fonte comune di vulnerabilità nelle applicazioni Web. In particolare, la configurazione Newtonsoft.Json
con TypeNameHandling.All
consente al client remoto di incorporare un'intera applicazione eseguibile all'interno del payload JSON stesso, in modo che durante la deserializzazione l'applicazione Web estrae ed esegue il codice incorporato. Per ottenere ulteriori informazioni, consultare Friday 13th JSON attacks PowerPoint e Friday the 13th JSON attacks details.
Query di percorso JSON non supportate
Il DOM JsonDocument
non supporta l'esecuzione di query tramite JSON Path.
In un DOM JsonNode ogni istanza JsonNode
ha un metodo GetPath
che restituisce un percorso a tale nodo. Non esiste tuttavia alcuna API predefinita per gestire le query basate su stringhe di query JSON Path.
Per ottenere ulteriori informazioni, vedere problema GitHub di dotnet/runtime #31068.
Alcuni limiti non configurabili
System.Text.Json imposta i limiti che non possono essere modificati per alcuni valori, ad esempio la dimensione massima del token in caratteri (166 MB) e in base 64 (125 MB). Per ottenere ulteiori informazioni, vedere JsonConstants
nel codice sorgente e nel problema di GitHub dotnet/runtime #39953.
NaN, Infinity, -Infinity
Newtonsoft analizza i token di stringa JSON NaN
, Infinity
e -Infinity
. Con System.Text.Json, usare JsonNumberHandling.AllowNamedFloatingPointLiterals. Per ottenere maggiori informazioni su come usare questa impostazione, vedere la sezione Consentire o scrivere numeri tra virgolette.
Usare GitHub Copilot per eseguire la migrazione
È possibile ottenere assistenza per la codifica da GitHub Copilot per convertire il codice all'interno dell'IDE.
Se si usa Visual Studio 2022 versione 17.8 o successiva, è possibile provare GitHub Copilot supportato da IA in Visual Studio per facilitare la migrazione del codice Newtonsoft.Json
da usare System.Text.Json
. Inviare la domanda e il codice da convertire come richiesta nella finestra di chat copilot, come nell'esempio seguente.
Nota
GitHub Copilot è supportato dall'IA, quindi sono possibili sorprese ed errori. Assicurarsi di verificare il codice o i suggerimenti generati. Per maggiori informazioni sull'uso generale di GitHub Copilot, sull'impatto sul prodotto, sulla supervisione umana e sulla privacy, vedere le Domande frequenti su GitHub Copilot.
Richiesta di esempio per Copilot Chat
convert the following code to use System.Text.Json
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2024, 08, 08);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string output = JsonConvert.SerializeObject(product);
Console.WriteLine(output);
Esempio di risposta di Copilot Chat
To convert the code to use System.Text.Json, you can use the JsonSerializer class. Here's the updated code:
using System;
using System.Text.Json;
public class Product
{
public string Name { get; set; }
public DateTime ExpiryDate { get; set; }
public decimal Price { get; set; }
public string[] Sizes { get; set; }
}
public class Program
{
public static void Main()
{
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2024, 08, 08);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string output = JsonSerializer.Serialize(product);
Console.WriteLine(output);
}
}
This code uses System.Text.Json.JsonSerializer.Serialize to convert the Product object to a JSON string.
Si noti che i risultati potrebbero essere diversi da quanto illustrato in queste risposte di esempio. I modelli di IA non sono deterministici, il che significa che possono restituire risposte diverse quando viene posta la stessa domanda. Questo potrebbe essere dovuto ad apprendimento e adattamento aggiuntivo nel tempo, alla variazione della lingua, ai cambiamenti nel contesto, ad esempio alla cronologia delle chat e altro ancora.
È possibile usare funzionalità di chat, ad esempio comandi barra, riferimenti e thread, per impostare la finalità e ottenere risposte migliori con il contesto con ambito.
Ad esempio, se il file di codice filename
è aperto nell'IDE, è possibile fare riferimento al file nel prompt a Copilot Chat con "convert #filename
to use System.Text.Json
". In alternativa, è possibile fare riferimento alla soluzione con "convert @workspace
to use System.Text.Json
" nella finestra di chat o nella chat inline.