Migrasi dari Newtonsoft.Json ke System.Text.Json

Artikel ini menunjukkan cara memigrasikan dari Newtonsoft.Json ke System.Text.Json.

Namespace System.Text.Json menyediakan fungsionalitas untuk membuat serialisasi ke dan deserialisasi dari JavaScript Object Notation (JSON). System.Text.Json Pustaka disertakan dalam runtime untuk .NET Core 3.1 dan versi yang lebih baru. Untuk kerangka kerja target lainnya, instal System.Text.Json paket NuGet. Paket ini mendukung:

  • .NET Standard 2.0 dan versi yang lebih baru
  • .NET Framework 4.7.2 dan versi yang lebih baru
  • .NET Core 2.0, 2.1, dan 2.2

System.Text.Json berfokus terutama pada kepatuhan performa, keamanan, dan standar. Memiliki beberapa perbedaan utama dalam perilaku default dan tidak bertujuan untuk memiliki kesamaan fitur dengan Newtonsoft.Json. Untuk beberapa skenario, System.Text.Json saat ini tidak memiliki fungsionalitas bawaan, tetapi ada solusi yang direkomendasikan. Untuk skenario lain, solusinya tidak praktis.

Kami berinvestasi dalam menambahkan fitur yang paling sering diminta. Jika aplikasi Anda bergantung pada fitur yang hilang, pertimbangkan untuk mengajukan masalah di repositori dotnet/runtime bahasa umum GitHub untuk mengetahui apakah dukungan untuk skenario Anda dapat ditambahkan.

Sebagian besar artikel ini adalah tentang cara menggunakan JsonSerializer API, tetapi juga mencakup panduan tentang cara menggunakan jenis JsonDocument (yang mewakili Model Objek Dokumen atau DOM), Utf8JsonReader, dan Utf8JsonWriter.

Dalam Visual Basic, Anda tidak dapat menggunakan Utf8JsonReader, yang juga berarti Anda tidak dapat menulis pengonversi kustom. Sebagian besar solusi yang disajikan di sini mengharuskan Anda menulis pengonversi kustom. Anda dapat menulis pengonversi kustom di C# dan mendaftarkannya dalam proyek Visual Basic. Untuk informasi selengkapnya, lihat dukungan (Visual Basic).

Tabel perbedaan

Tabel berikut ini mencantumkan Newtonsoft.Json fitur dan System.Text.Json persamaannya. Yang setara termasuk dalam kategori berikut:

  • ✔️ Didukung oleh fungsionalitas bawaan. Mendapatkan perilaku serupa dari System.Text.Json mungkin memerlukan penggunaan atribut atau opsi global.
  • ⚠️ Tidak didukung, tetapi solusi dimungkinkan. Solusinya adalah pengonversi kustom, yang mungkin tidak menyediakan kesamaan lengkap dengan Newtonsoft.Json fungsionalitas. Untuk beberapa di antaranya, kode sampel disediakan sebagai contoh. Jika Anda mengandalkan Newtonsoft.Json fitur-fitur ini, migrasi akan memerlukan modifikasi pada model objek .NET atau perubahan kode lainnya.
  • ❌ Tidak didukung, dan solusinya tidak praktis atau mungkin. Jika Anda mengandalkan Newtonsoft.Json fitur-fitur ini, migrasi tidak akan memungkinkan tanpa perubahan yang signifikan.
Newtonsoft.Json fitur System.Text.Json persamaan
Deserialisasi tak peka huruf besar/kecil secara default ✔️ Pengaturan global PropertyNameCaseInsensitive
Nama properti camel-case ✔️ Pengaturan global PropertyNamingPolicy
Nama properti camel-case ✔️ Kebijakan penamaan kasus ular
Pelepasan karakter minimal ✔️ Pelepasan karakter yang ketat, dapat dikonfigurasi
NullValueHandling.Ignore pengaturan global ✔️ Opsi global DefaultIgnoreCondition
Izinkan komentar ✔️ Pengaturan global ReadCommentHandling
Perbolehkan koma berikutnya ✔️ Pengaturan global AllowTrailingCommas
Pendaftaran pengonversi kustom ✔️ Urutan prioritas berbeda
Kedalaman maksimum default 64, dapat dikonfigurasi ✔️ Kedalaman maksimum default 64, dapat dikonfigurasi
PreserveReferencesHandling pengaturan global ✔️ Pengaturan global ReferenceHandling
Serialisasi atau deserialisasi angka dalam tanda kutip ✔️ Pengaturan global NumberHandling, atribut [JsonNumberHandling]
Deserialisasi ke kelas dan struktur yang tidak dapat diubah ✔️ JsonConstructor, Rekaman C# 9
Dukungan untuk bidang ✔️ Pengaturan global IncludeFields, atribut [JsonInclude]
DefaultValueHandling pengaturan global ✔️ Opsi global DefaultIgnoreCondition
NullValueHandling pengaturan pada [JsonProperty] ✔️ Atribut JsonIgnore
DefaultValueHandling pengaturan pada [JsonProperty] ✔️ Atribut JsonIgnore
Deserialisasi Dictionary dengan kunci non-string ✔️ Didukung
Dukungan untuk setter dan getter properti non-publik ✔️ Atribut JsonInclude
atribut [JsonConstructor] ✔️ Atribut [JsonConstructor]
ReferenceLoopHandling pengaturan global ✔️ Pengaturan global ReferenceHandling
Panggilan balik ✔️ Panggilan balik
Nan, Infinity, -Infinity ✔️ Didukung
Required pengaturan pada [JsonProperty] atribut ✔️ Atribut [JsonRequired] dan pengubah yang diperlukan C#
DefaultContractResolver mengabaikan properti ✔️ Kelas DefaultJsonTypeInfoResolver
Serialisasi polimorfik ✔️ Atribut [JsonDerivedType]
Deserialisasi polimorfik ✔️ Ketik diskriminator pada atribut [JsonDerivedType]
Deserialisasi nilai enum string ✔️ Mendeserialisasi nilai enum string
MissingMemberHandling pengaturan global ✔️ Menangani anggota yang hilang
Mengisi properti tanpa setter ✔️ Mengisi properti tanpa setter
ObjectCreationHandling pengaturan global ✔️ Gunakan kembali daripada mengganti properti
Dukungan untuk berbagai jenis ⚠️ Beberapa jenis memerlukan pengonversi kustom
Deserialisasi jenis yang disimpulkan ke object properti ⚠️ Tidak didukung, solusi, sampel
Deserialisasi JSON null harfiah ke jenis nilai yang tidak dapat diubah ke null ⚠️ Tidak didukung, solusi, sampel
DateTimeZoneHandling, DateFormatString pengaturan ⚠️ Tidak didukung, solusi, sampel
metode JsonConvert.PopulateObject ⚠️ Tidak didukung, solusi
Dukungan untuk System.Runtime.Serialization atribut ⚠️ Tidak didukung, solusi, sampel
JsonObjectAttribute ⚠️ Tidak didukung, solusi
Izinkan nama properti tanpa tanda kutip Tidak didukung oleh desain
Izinkan tanda kutip tunggal di sekitar nilai string Tidak didukung oleh desain
Izinkan nilai JSON non-string untuk properti string Tidak didukung oleh desain
TypeNameHandling.All pengaturan global Tidak didukung oleh desain
Dukungan untuk JsonPath kueri Tidak didukung
Batas yang dapat dikonfigurasi Tidak didukung
Newtonsoft.Json fitur System.Text.Json persamaan
Deserialisasi tak peka huruf besar/kecil secara default ✔️ Pengaturan global PropertyNameCaseInsensitive
Nama properti camel-case ✔️ Pengaturan global PropertyNamingPolicy
Pelepasan karakter minimal ✔️ Pelepasan karakter yang ketat, dapat dikonfigurasi
NullValueHandling.Ignore pengaturan global ✔️ Opsi global DefaultIgnoreCondition
Izinkan komentar ✔️ Pengaturan global ReadCommentHandling
Perbolehkan koma berikutnya ✔️ Pengaturan global AllowTrailingCommas
Pendaftaran pengonversi kustom ✔️ Urutan prioritas berbeda
Kedalaman maksimum default 64, dapat dikonfigurasi ✔️ Kedalaman maksimum default 64, dapat dikonfigurasi
PreserveReferencesHandling pengaturan global ✔️ Pengaturan global ReferenceHandling
Serialisasi atau deserialisasi angka dalam tanda kutip ✔️ Pengaturan global NumberHandling, atribut [JsonNumberHandling]
Deserialisasi ke kelas dan struktur yang tidak dapat diubah ✔️ JsonConstructor, Rekaman C# 9
Dukungan untuk bidang ✔️ Pengaturan global IncludeFields, atribut [JsonInclude]
DefaultValueHandling pengaturan global ✔️ Opsi global DefaultIgnoreCondition
NullValueHandling pengaturan pada [JsonProperty] ✔️ Atribut JsonIgnore
DefaultValueHandling pengaturan pada [JsonProperty] ✔️ Atribut JsonIgnore
Deserialisasi Dictionary dengan kunci non-string ✔️ Didukung
Dukungan untuk setter dan getter properti non-publik ✔️ Atribut JsonInclude
atribut [JsonConstructor] ✔️ Atribut [JsonConstructor]
ReferenceLoopHandling pengaturan global ✔️ Pengaturan global ReferenceHandling
Panggilan balik ✔️ Panggilan balik
Nan, Infinity, -Infinity ✔️ Didukung
Required pengaturan pada [JsonProperty] atribut ✔️ Atribut [JsonRequired] dan pengubah yang diperlukan C#
DefaultContractResolver mengabaikan properti ✔️ Kelas DefaultJsonTypeInfoResolver
Serialisasi polimorfik ✔️ Atribut [JsonDerivedType]
Deserialisasi polimorfik ✔️ Ketik diskriminator pada atribut [JsonDerivedType]
Deserialisasi nilai enum string ✔️ Mendeserialisasi nilai enum string
Dukungan untuk berbagai jenis ⚠️ Beberapa jenis memerlukan pengonversi kustom
Deserialisasi jenis yang disimpulkan ke object properti ⚠️ Tidak didukung, solusi, sampel
Deserialisasi JSON null harfiah ke jenis nilai yang tidak dapat diubah ke null ⚠️ Tidak didukung, solusi, sampel
DateTimeZoneHandling, DateFormatString pengaturan ⚠️ Tidak didukung, solusi, sampel
metode JsonConvert.PopulateObject ⚠️ Tidak didukung, solusi
ObjectCreationHandling pengaturan global ⚠️ Tidak didukung, solusi
Tambahkan ke koleksi tanpa setter ⚠️ Tidak didukung, solusi
Nama properti camel-case ⚠️ Tidak didukung, solusi
Dukungan untuk System.Runtime.Serialization atribut ⚠️ Tidak didukung, solusi, sampel
MissingMemberHandling pengaturan global ⚠️ Tidak didukung, solusi, sampel
JsonObjectAttribute ⚠️ Tidak didukung, solusi
Izinkan nama properti tanpa tanda kutip Tidak didukung oleh desain
Izinkan tanda kutip tunggal di sekitar nilai string Tidak didukung oleh desain
Izinkan nilai JSON non-string untuk properti string Tidak didukung oleh desain
TypeNameHandling.All pengaturan global Tidak didukung oleh desain
Dukungan untuk JsonPath kueri Tidak didukung
Batas yang dapat dikonfigurasi Tidak didukung
Newtonsoft.Json fitur System.Text.Json persamaan
Deserialisasi tak peka huruf besar/kecil secara default ✔️ Pengaturan global PropertyNameCaseInsensitive
Nama properti camel-case ✔️ Pengaturan global PropertyNamingPolicy
Pelepasan karakter minimal ✔️ Pelepasan karakter yang ketat, dapat dikonfigurasi
NullValueHandling.Ignore pengaturan global ✔️ Opsi global DefaultIgnoreCondition
Izinkan komentar ✔️ Pengaturan global ReadCommentHandling
Perbolehkan koma berikutnya ✔️ Pengaturan global AllowTrailingCommas
Pendaftaran pengonversi kustom ✔️ Urutan prioritas berbeda
Kedalaman maksimum default 64, dapat dikonfigurasi ✔️ Kedalaman maksimum default 64, dapat dikonfigurasi
PreserveReferencesHandling pengaturan global ✔️ Pengaturan global ReferenceHandling
Serialisasi atau deserialisasi angka dalam tanda kutip ✔️ Pengaturan global NumberHandling, atribut [JsonNumberHandling]
Deserialisasi ke kelas dan struktur yang tidak dapat diubah ✔️ JsonConstructor, Rekaman C# 9
Dukungan untuk bidang ✔️ Pengaturan global IncludeFields, atribut [JsonInclude]
DefaultValueHandling pengaturan global ✔️ Opsi global DefaultIgnoreCondition
NullValueHandling pengaturan pada [JsonProperty] ✔️ Atribut JsonIgnore
DefaultValueHandling pengaturan pada [JsonProperty] ✔️ Atribut JsonIgnore
Deserialisasi Dictionary dengan kunci non-string ✔️ Didukung
Dukungan untuk setter dan getter properti non-publik ✔️ Atribut JsonInclude
atribut [JsonConstructor] ✔️ Atribut [JsonConstructor]
ReferenceLoopHandling pengaturan global ✔️ Pengaturan global ReferenceHandling
Panggilan balik ✔️ Panggilan balik
Nan, Infinity, -Infinity ✔️ Didukung
Deserialisasi nilai enum string ✔️ Mendeserialisasi nilai enum string
Dukungan untuk berbagai jenis ⚠️ Beberapa jenis memerlukan pengonversi kustom
Serialisasi polimorfik ⚠️ Tidak didukung, solusi, sampel
Deserialisasi polimorfik ⚠️ Tidak didukung, solusi, sampel
Deserialisasi jenis yang disimpulkan ke object properti ⚠️ Tidak didukung, solusi, sampel
Deserialisasi JSON null harfiah ke jenis nilai yang tidak dapat diubah ke null ⚠️ Tidak didukung, solusi, sampel
Required pengaturan pada [JsonProperty] atribut ⚠️ Tidak didukung, solusi, sampel
DefaultContractResolver mengabaikan properti ⚠️ Tidak didukung, solusi, sampel
DateTimeZoneHandling, DateFormatString pengaturan ⚠️ Tidak didukung, solusi, sampel
metode JsonConvert.PopulateObject ⚠️ Tidak didukung, solusi
ObjectCreationHandling pengaturan global ⚠️ Tidak didukung, solusi
Tambahkan ke koleksi tanpa setter ⚠️ Tidak didukung, solusi
Nama properti camel-case ⚠️ Tidak didukung, solusi
JsonObjectAttribute ⚠️ Tidak didukung, solusi
Dukungan untuk System.Runtime.Serialization atribut Tidak didukung
MissingMemberHandling pengaturan global Tidak didukung
Izinkan nama properti tanpa tanda kutip Tidak didukung oleh desain
Izinkan tanda kutip tunggal di sekitar nilai string Tidak didukung oleh desain
Izinkan nilai JSON non-string untuk properti string Tidak didukung oleh desain
TypeNameHandling.All pengaturan global Tidak didukung oleh desain
Dukungan untuk JsonPath kueri Tidak didukung
Batas yang dapat dikonfigurasi Tidak didukung

Ini bukanlah daftar lengkap Newtonsoft.Json fitur. Daftar ini mencakup banyak skenario yang telah diminta dalam masalah GitHub atau kiriman StackOverflow. Jika Anda menerapkan solusi untuk salah satu skenario yang tercantum di sini yang saat ini tidak memiliki kode sampel, dan jika Anda ingin membagikan solusi Anda, pilih Halaman ini di bagian Umpan Balik di bagian bawah halaman ini. Hal tersebut membuat masalah dalam dokumentasi repositori GitHub ini dan mencantumkannya pada bagian Umpan Balik di halaman ini juga.

Perbedaan perilaku default

System.Text.Json bersifat ketat secara default dan menghindari tebakan atau interpretasi atas nama pemanggil, menekankan perilaku deterministik. Pustaka sengaja dirancang dengan cara ini demi performa dan keamanan. Newtonsoft.Json bersifat fleksibel secara default. Perbedaan mendasar dalam desain ini berada di belakang banyak perbedaan spesifik berikut dalam perilaku default.

Deserialisasi yang tidak peka huruf besar/kecil

Selama deserialisasi, Newtonsoft.Json melakukan pencocokan nama properti tak peka huruf besar/kecil cocok secara default. Defaultnya System.Text.Json adalah peka huruf besar/kecil, yang memberikan performa yang lebih baik karena melakukan kecocokan yang tepat. Untuk informasi tentang cara melakukan pencocokan tak peka huruf besar/kecil, lihat Pencocokan properti yang tidak peka huruf besar/kecil.

Jika Anda menggunakan System.Text.Json secara tidak langsung dengan menggunakan ASP.NET Core, Anda tidak perlu melakukan apa pun untuk mendapatkan perilaku seperti Newtonsoft.Json. ASP.NET Core menentukan pengaturan untuk nama properti camel-casing dan pencocokan tidak peka huruf besar/kecil saat menggunakan System.Text.Json.

ASP.NET Core juga memungkinkan deserialisasi angka yang dikutip secara default.

Pelepasan karakter minimal

Selama serialisasi, Newtonsoft.Json relatif permisif untuk membiarkan karakter melewatinya tanpa melepaskannya. Artinya, ia tidak menggantinya dengan \uxxxx di mana xxxx adalah titik kode karakter. Di mana ia melarikan diri dari mereka, ia melakukannya dengan memancarkan \ sebelum karakter (misalnya, " menjadi \"). System.Text.Json lolos dari lebih banyak karakter secara default untuk memberikan perlindungan pertahanan mendalam terhadap scripting lintas situs (XSS) atau serangan penyingkapan informasi dan melakukannya dengan menggunakan urutan enam karakter. System.Text.Json lolos dari semua karakter non-ASCII secara default, jadi Anda tidak perlu melakukan apa pun jika Anda menggunakan StringEscapeHandling.EscapeNonAscii pada Newtonsoft.Json. System.Text.Json juga lolos dari karakter sensitif HTML, secara default. Untuk informasi tentang cara mengambil alih perilaku default System.Text.Json, lihat Menyesuaikan pengodean karakter.

Komentar

Selama deserialisasi, Newtonsoft.Json mengabaikan komentar di JSON secara default. Defaultnya System.Text.Json adalah memberikan pengecualian untuk komentar karena spesifikasi RFC 8259 tidak menyertakannya. Untuk informasi tentang cara mengizinkan komentar, lihat Mengizinkan komentar dan koma berikutnya.

Koma berikutnya

Selama deserialisasi, Newtonsoft.Json mengabaikan koma berikutnya secara default. Ia juga mengabaikan beberapa koma berikutnya (misalnya, [{"Color":"Red"},{"Color":"Green"},,]). Defaultnya System.Text.Json adalah memberikan pengecualian untuk komentar karena spesifikasi RFC 8259 tidak menyertakannya. Untuk informasi tentang cara membuat System.Text.Json menerimanya, lihat Mengizinkan komentar dan koma berikutnya. Tidak ada cara untuk mengizinkan beberapa koma berikutnya.

Prioritas pendaftaran pengonversi

Prioritas pendaftaran Newtonsoft.Json untuk pengonversi kustom adalah sebagai berikut:

  • Atribut pada properti
  • Atribut pada jenis
  • Koleksi pengonversi

Urutan ini berarti bahwa pengonversi kustom dalam Converters koleksi ditimpa oleh pengonversi yang terdaftar dengan menerapkan atribut pada tingkat jenis. Kedua pendaftaran tersebut ditimpa oleh atribut di tingkat properti.

Prioritas pendaftaran System.Text.Json untuk pengonversi kustom berbeda:

  • Atribut pada properti
  • Converters koleksi
  • Atribut pada jenis

Perbedaannya di sini adalah bahwa pengonversi kustom dalam Converters koleksi mengambil alih atribut pada tingkat jenis. Tujuan di balik urutan prioritas ini adalah untuk membuat perubahan run-time mengambil alih pilihan waktu desain. Tidak ada cara untuk mengubah prioritas.

Untuk informasi selengkapnya tentang pendaftaran pengonversi kustom, lihat Mendaftarkan pengonversi kustom.

Kedalaman maksimal

Versi Newtonsoft.Json terbaru memiliki batas kedalaman maksimum 64 secara default. System.Text.Json juga memiliki batas default 64, dan dapat dikonfigurasi dengan mengatur JsonSerializerOptions.MaxDepth.

Jika Anda menggunakan System.Text.Json secara tidak langsung dengan menggunakan ASP.NET Core, batas kedalaman maksimum default adalah 32. Nilai default sama dengan yang digunakan untuk pengikatan model dan diatur di kelas JsonOptions.

String JSON (nama properti dan nilai string)

Selama deserialisasi, Newtonsoft.Json menerima nama properti yang dikelilingi oleh tanda kutip ganda, tanda kutip tunggal, atau tanpa tanda kutip. Ia menerima nilai string yang dikelilingi oleh tanda kutip ganda atau tanda kutip tunggal. Misalnya, Newtonsoft.Json menerima JSON berikut:

{
  "name1": "value",
  'name2': "value",
  name3: 'value'
}

System.Text.Json hanya menerima nama properti dan nilai string dalam tanda kutip ganda karena format tersebut diperlukan oleh spesifikasi RFC 8259 dan merupakan satu-satunya format yang dianggap sebagai JSON yang valid.

Nilai yang diapit dalam tanda kutip tunggal menghasilkan JsonException dengan pesan berikut:

''' is an invalid start of a value.

Nilai non-string untuk properti string

Newtonsoft.Json menerima nilai non-string, seperti angka atau literal true dan false, untuk deserialisasi ke properti jenis string. Berikut adalah contoh JSON yang Newtonsoft.Json berhasil mendeserialisasi ke kelas berikut:

{
  "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 tidak mendeserialisasi nilai non-string ke dalam properti string. Nilai non-string yang diterima untuk bidang string menghasilkan JsonException dengan pesan berikut:

The JSON value could not be converted to System.String.

Skenario menggunakan JsonSerializer

Beberapa skenario berikut tidak didukung oleh fungsionalitas bawaan, tetapi solusinya memungkinkan. Solusinya adalah pengonversi kustom, yang mungkin tidak menyediakan kesamaan lengkap dengan Newtonsoft.Json fungsionalitas. Untuk beberapa di antaranya, kode sampel disediakan sebagai contoh. Jika Anda mengandalkan Newtonsoft.Json fitur-fitur ini, migrasi akan memerlukan modifikasi pada model objek .NET atau perubahan kode lainnya.

Untuk beberapa skenario berikut, solusinya tidak praktis atau memungkinkan. Jika Anda mengandalkan Newtonsoft.Json fitur-fitur ini, migrasi tidak akan memungkinkan tanpa perubahan yang signifikan.

Izinkan atau tulis angka dalam tanda kutip

Newtonsoft.Json dapat membuat serialisasi atau mendeserialisasi angka yang diwakili oleh string JSON (dikelilingi oleh tanda kutip). Misalnya, ia dapat menerima: {"DegreesCelsius":"23"} alih-alih {"DegreesCelsius":23}. Untuk mengaktifkan perilaku tersebut pada System.Text.Json, atur JsonSerializerOptions.NumberHandling ke WriteAsString atau AllowReadingFromString, atau gunakan atribut [JsonNumberHandling].

Jika Anda menggunakan System.Text.Json secara tidak langsung dengan menggunakan ASP.NET Core, Anda tidak perlu melakukan apa pun untuk mendapatkan perilaku seperti Newtonsoft.Json. ASP.NET Core menentukan default web saat menggunakan System.Text.Json, dan default web memungkinkan angka yang dikutip.

Untuk informasi selengkapnya, lihat Mengizinkan atau menulis angka dalam tanda kutip.

Tentukan konstruktor yang akan digunakan saat deserialisasi

Atribut Newtonsoft.Json[JsonConstructor] memungkinkan Anda menentukan konstruktor mana yang akan dipanggil saat deserialisasi ke POCO.

System.Text.Json juga memiliki atribut [JsonConstructor]. Untuk informasi selengkapnya, lihat Jenis dan Rekaman yang Tidak Dapat Diubah.

Mengabaikan properti secara kondisional

Newtonsoft.Json memiliki beberapa cara untuk mengabaikan properti secara kondisional pada serialisasi atau deserialisasi:

  • DefaultContractResolver memungkinkan Anda memilih properti untuk disertakan atau diabaikan, berdasarkan kriteria arbitrer.
  • Pengaturan NullValueHandling dan DefaultValueHandling pada JsonSerializerSettings memungkinkan Anda menentukan bahwa semua properti nilai null atau nilai default harus diabaikan.
  • Pengaturan NullValueHandling dan DefaultValueHandling pada [JsonProperty] atribut memungkinkan Anda menentukan properti individual yang harus diabaikan saat diatur ke null atau nilai default.

System.Text.Json menyediakan cara berikut untuk mengabaikan properti atau bidang saat melakukan serialisasi:

Selain itu, dalam .NET 7 dan versi yang lebih baru, Anda dapat menyesuaikan kontrak JSON untuk mengabaikan properti berdasarkan kriteria arbitrer. Untuk informasi selengkapnya, lihat Kontrak kustom.

Opsi ini tidak memungkinkan Anda mengabaikan properti yang dipilih berdasarkan kriteria arbitrer yang dievaluasi pada waktu proses.

Bidang publik dan non-publik

Newtonsoft.Json dapat menserialisasi dan mendeserialisasi bidang serta properti.

Pada System.Text.Json, gunakan JsonSerializerOptions.IncludeFields pengaturan global atau [JsonInclude] untuk menyertakan bidang saat melakukan serialisasi atau deserialisasi. Sebagai contoh, lihat Menyertakan bidang.

Mempertahankan referensi objek dan menangani perulangan

Secara default, Newtonsoft.Json melakukan serialisasi berdasarkan nilai. Misalnya, jika objek berisi dua properti yang berisi referensi ke Person objek yang sama, nilai Person dari properti objek tersebut diduplikasi di JSON.

Newtonsoft.Json memiliki PreserveReferencesHandling pengaturan yang JsonSerializerSettings memungkinkan Anda membuat serialisasi berdasarkan referensi:

  • Metadata pengidentifikasi ditambahkan ke JSON yang dibuat untuk Person objek pertama.
  • JSON yang dibuat untuk objek kedua Person berisi referensi ke pengidentifikasi tersebut alih-alih nilai properti.

Newtonsoft.Json juga memiliki ReferenceLoopHandling pengaturan yang memungkinkan Anda mengabaikan referensi melingkar daripada memberikan pengecualian.

Untuk mempertahankan referensi dan menangani referensi melingkar pada System.Text.Json, atur JsonSerializerOptions.ReferenceHandler ke Preserve. Pengaturan ReferenceHandler.Preserve setara denganPreserveReferencesHandling = PreserveReferencesHandling.All pada Newtonsoft.Json.

Opsi ReferenceHandler.IgnoreCycles ini memiliki perilaku yang mirip dengan Newtonsoft.JsonReferenceLoopHandling.Ignore. Salah satu perbedaannya adalah implementasi System.Text.Json menggantikan perulangan referensi dengan null token JSON alih-alih mengabaikan referensi objek. Untuk informasi lebih lanjut, lihat Abaikan referensi melingkar.

Seperti halnya Newtonsoft.JsonReferenceResolver, kelas System.Text.Json.Serialization.ReferenceResolver menentukan perilaku mempertahankan referensi pada serialisasi dan deserialisasi. Buat kelas turunan untuk menentukan perilaku kustom. Sebagai contoh, lihat GuidReferenceResolver.

Beberapa fitur terkait Newtonsoft.Json tidak didukung:

Untuk informasi selengkapnya, lihat Mempertahankan referensi dan menangani referensi melingkar.

Kamus dengan kunci non-string

Baik Newtonsoft.Json dan System.Text.Json mendukung koleksi jenis Dictionary<TKey, TValue>. Namun, dalam System.Text.Json, TKey harus berupa jenis primitif, bukan jenis kustom. Untuk informasi selengkapnya, lihat Jenis kunci yang didukung.

Perhatian

Deserialisasi ke Dictionary<TKey, TValue> di mana TKey berjenis apa pun selain string dapat menyebabkan kerentanan keamanan dalam aplikasi pemakai. Untuk informasi selengkapnya, lihat dotnet/runtime#4761.

Jenis tanpa dukungan bawaan

System.Text.Json tidak menyediakan dukungan bawaan untuk jenis berikut:

Pengonversi kustom dapat diimplementasikan untuk jenis yang tidak memiliki dukungan bawaan.

Serialisasi polimorfik

Newtonsoft.Json secara otomatis melakukan serialisasi polimorfik. Mulai dari .NET 7, System.Text.Json mendukung serialisasi polimorfik melalui JsonDerivedTypeAttribute atribut . Untuk informasi selengkapnya, lihat Membuat serialisasi properti kelas turunan.

Deserialisasi polimorfik

Newtonsoft.Json memiliki TypeNameHandling pengaturan yang menambahkan metadata nama-jenis ke JSON saat melakukan serialisasi. Ia menggunakan metadata saat deserialisasi untuk melakukan deserialisasi polimorfik. Mulai dari .NET 7, System.Text.Json bergantung pada jenis informasi diskriminator untuk melakukan deserialisasi polimorfik. Metadata ini dipancarkan dalam JSON dan kemudian digunakan selama deserialisasi untuk menentukan apakah akan mendeserialisasi ke jenis dasar atau jenis turunan. Untuk informasi selengkapnya, lihat Membuat serialisasi properti kelas turunan.

Untuk mendukung deserialisasi polimorfik dalam versi .NET yang lebih lama, buat pengonversi seperti contoh dalam Cara menulis pengonversi kustom.

Mendeserialisasi nilai enum string

Secara default, System.Text.Json tidak mendukung deserialisasi nilai enum string, sedangkan Newtonsoft.Json tidak. Misalnya, kode berikut melempar :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
}

Namun, Anda dapat mengaktifkan deserialisasi nilai enum string dengan menggunakan pengonversi JsonStringEnumConverter . Untuk informasi selengkapnya, lihat Enums sebagai string.

Deserialisasi properti objek

Ketika Newtonsoft.Json deserialisasi ke Object, maka akan:

  • Menyimpulkan jenis nilai primitif dalam payload JSON (selain null) dan mengembalikan string, long, double, boolean, atau DateTime yang tersimpan sebagai objek yang dikemas. Nilai primitif adalah nilai JSON tunggal seperti angka JSON, string, true, false, atau null.
  • Mengembalikan JObject atau JArray untuk nilai kompleks dalam payload JSON. Nilai kompleks adalah kumpulan pasangan kunci-nilai JSON dalam kurung kurawal ({}) atau daftar nilai dalam tanda kurung siku ([]). Properti dan nilai dalam kurung kurawal atau kurung siku dapat memiliki properti atau nilai tambahan.
  • Mengembalikan referensi null saat payload memiliki null harfiah JSON.

System.Text.Json menyimpan JsonElement yang sudah dikemas untuk nilai primitif dan kompleks setiap kali melakukan deserialisasi ke Object, misalnya:

  • Sebuah object properti.
  • Sebuah object nilai kamus.
  • Sebuah object nilai array.
  • Akar object.

Namun, System.Text.Json memperlakukan null sama halnya dengan Newtonsoft.Json dan mengembalikan referensi null ketika payload memiliki null harfiah JSON di dalamnya.

Untuk menerapkan inferensi jenis untuk object properti, buat pengonversi seperti contoh dalam Cara menulis pengonversi kustom.

Deserialisasi null ke tipe yang tidak dapat diubah ke null

Newtonsoft.Json tidak memberikan pengecualian dalam skenario berikut:

  • NullValueHandling diatur ke Ignore, dan
  • Selama deserialisasi, JSON berisi nilai null untuk jenis nilai yang tidak dapat diubah ke null.

Dalam skenario yang sama, System.Text.Json memang memberikan pengecualian. (Pengaturan penanganan null yang sesuai pada System.Text.Json adalah JsonSerializerOptions.IgnoreNullValues = true.)

Jika Anda memiliki jenis target, solusi terbaik adalah membuat properti yang bersangkutan dapat diubah ke null (misalnya, mengubah int ke int?).

Solusi lain adalah membuat pengonversi untuk jenis tersebut, seperti contoh berikut yang menangani nilai null untuk DateTimeOffset jenis:

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);
    }
}

Daftarkan pengonversi kustom ini dengan menggunakan atribut pada properti individual atau dengan menambahkan pengonversi ke Converters koleksi.

Catatan: Pengonversi sebelumnya menangani nilai null secara berbeda dari Newtonsoft.Json yang dilakukan untuk POCO yang menentukan nilai default. Misalnya, kode berikut mewakili objek target Anda:

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; }
}

Dan misalkan JSON berikut dideserialisasi dengan menggunakan pengonversi sebelumnya:

{
  "Date": null,
  "TemperatureCelsius": 25,
  "Summary": null
}

Setelah deserialisasi, properti Date memiliki 1/1/0001 (default(DateTimeOffset)), yaitu, nilai yang ditetapkan dalam konstruktor tertimpa. Dengan POCO dan JSON yang sama, Newtonsoft.Json deserialisasi akan meninggalkan 1/1/2001 pada Date properti.

Deserialisasi ke kelas dan struktur yang tidak dapat diubah

Newtonsoft.Json dapat mendeserialisasi ke kelas dan struktur yang tidak dapat diubah karena dapat menggunakan konstruktor yang memiliki parameter.

Pada System.Text.Json, gunakan atribut [JsonConstructor] untuk menentukan penggunaan konstruktor berparameter. Rekaman di C# 9 juga tidak dapat diubah dan didukung sebagai target deserialisasi. Untuk informasi selengkapnya, lihat Jenis dan Rekaman yang Tidak Dapat Diubah.

Properti yang diperlukan

Dalam Newtonsoft.Json, Anda menentukan agar suatu properti diperlukan dengan mengatur Required pada [JsonProperty] atribut. Newtonsoft.Json memberikan pengecualian jika tidak ada nilai yang diterima di JSON untuk properti yang ditandai sebagaimana diperlukan.

Mulai dari .NET 7, Anda dapat menggunakan pengubah C# required atau JsonRequiredAttribute atribut pada properti yang diperlukan. System.Text.Json memberikan pengecualian jika payload JSON tidak berisi nilai untuk properti yang ditandai. Untuk informasi selengkapnya, lihat Properti yang diperlukan.

System.Text.Json tidak memberikan pengecualian jika tidak ada nilai yang diterima untuk salah satu properti dari jenis target. Misalnya, jika Anda memiliki WeatherForecast kelas:

public class WeatherForecast
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

JSON berikut dideserialisasi tanpa kesalahan:

{
    "TemperatureCelsius": 25,
    "Summary": "Hot"
}

Untuk membuat deserialisasi gagal jika tidak ada Date properti di JSON, pilih salah satu opsi berikut:

Contoh kode pengonversi berikut memberikan pengecualian jika Date properti tidak diatur setelah deserialisasi selesai:

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);
        }
    }
}

Daftarkan pengonversi kustom ini dengan menambahkan pengonversi ke JsonSerializerOptions.Converters koleksi.

Pola pemanggilan pengonversi secara rekursif ini mengharuskan Anda mendaftarkan pengonversi dengan menggunakan JsonSerializerOptions, bukan dengan menggunakan atribut. Jika Anda mendaftarkan pengonversi dengan menggunakan atribut, pengonversi kustom akan memanggil secara rekursif. Hasilnya adalah perulangan tak terbatas yang berakhir dengan pengecualian stack overflow.

Saat Anda mendaftarkan pengonversi dengan menggunakan objek opsi, hindari perulangan tak terbatas dengan tidak meneruskan objek opsi saat memanggil Serialize atau Deserializesecara rekursif. Objek opsi berisi Converters koleksi. Jika Anda meneruskannya ke Serialize atau Deserialize, pengonversi kustom memanggil dirinya sendiri, membuat perulangan tak terbatas yang menghasilkan pengecualian stack overflow. Jika opsi default tidak layak, buat instans baru dari opsi dengan pengaturan yang Anda butuhkan. Pendekatan ini akan berjalan lambat karena setiap instans baru menjadi cache secara independen.

Ada pola alternatif yang dapat menggunakan JsonConverterAttribute pendaftaran pada kelas yang akan dikonversi. Dalam pendekatan ini, kode pengonversi memanggil Serialize atau Deserialize pada kelas yang berasal dari kelas yang akan dikonversi. Kelas turunan tidak menerapkan JsonConverterAttribute padanya. Dalam contoh berikut dari alternatif ini:

  • WeatherForecastWithRequiredPropertyConverterAttribute adalah kelas yang akan dideserialisasi dan telah menerapkan JsonConverterAttribute padanya.
  • WeatherForecastWithoutRequiredPropertyConverterAttribute adalah kelas turunan yang tidak memiliki atribut pengonversi.
  • Kode dalam panggilan Serialize konverter dan Deserialize aktif WeatherForecastWithoutRequiredPropertyConverterAttribute untuk menghindari perulangan tak terbatas. Terdapat biaya performa untuk pendekatan ini pada serialisasi karena instansiasi objek tambahan dan penyalinan nilai properti.

Berikut adalah jenis 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
{
}

Dan inilah pengonversinya:

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);
        }
    }
}

Pengonversi properti yang diperlukan akan memerlukan logika tambahan jika Anda perlu menangani atribut seperti [JsonIgnore] atau opsi yang berbeda, seperti encoder kustom. Selain itu, kode contoh tidak menangani properti yang nilai defaultnya diatur dalam konstruktor. Dan pendekatan ini tidak membedakan antara skenario berikut:

  • Properti hilang dari JSON.
  • Properti untuk jenis yang tidak dapat diubah ke null ada pada JSON, tetapi nilainya adalah default untuk jenis tersebut, seperti nol untuk int.
  • Properti untuk jenis nilai yang dapat diubah ke null ada di JSON, tetapi nilainya null.

Catatan

Jika Anda menggunakan System.Text.Json dari pengontrol ASP.NET Core, Anda mungkin dapat menggunakan [Required] atribut pada properti kelas model alih-alih menerapkan System.Text.Json pengonversi.

Tentukan format tanggal

Newtonsoft.Json menyediakan beberapa cara untuk mengontrol bagaimana properti jenis DateTime dan DateTimeOffset diserialisasikan dan dideserialisasi:

  • DateTimeZoneHandling Pengaturan dapat digunakan untuk menserialisasikan semua DateTime nilai sebagai tanggal UTC.
  • DateFormatStringPengaturan dan DateTime pengonversi dapat digunakan untuk menyesuaikan format string tanggal.

System.Text.Json mendukung ISO 8601-1:2019, termasuk profil RFC 3339. Format ini diadopsi secara luas, tidak ambigu, dan melakukan perjalanan pulang pergi dengan tepat. Untuk menggunakan format lain, buat pengonversi kustom. Misalnya, pengonversi berikut menserialisasikan dan mendeserialisasi JSON yang menggunakan format epoch Unix dengan atau tanpa offset zona waktu (nilai seperti /Date(1590863400000-0700)/ atau /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);
    }
}

Untuk informasi selengkapnya, lihat Dukungan DateTime dan DateTimeOffset di System.Text.Json.

Panggilan balik

Newtonsoft.Json memungkinkan Anda menjalankan kode kustom di beberapa titik dalam proses serialisasi atau deserialisasi:

  • OnDeserializing (ketika mulai mendeserialisasi objek)
  • OnDeserialized (ketika selesai mendeserialisasi objek)
  • OnSerializing (ketika mulai menserialisasikan objek)
  • OnSerialized (ketika selesai menserialisasikan objek)

System.Text.Json mengekspos pemberitahuan yang sama selama serialisasi dan deserialisasi. Untuk menggunakannya, terapkan satu atau beberapa antarmuka berikut dari System.Text.Json.Serialization namespace layanan:

Berikut adalah contoh yang memeriksa properti null dan menulis pesan di awal dan akhir serialisasi dan deserialisasi:

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=

Kode OnDeserializing tidak memiliki akses ke instans POCO baru. Untuk memanipulasi instans POCO baru di awal deserialisasi, letakkan kode tersebut di konstruktor POCO.

Dukungan untuk setter dan getter properti non-publik

Newtonsoft.Json dapat menggunakan setter properti privat dan internal dan getter melalui JsonProperty atribut.

System.Text.Json mendukung setter properti privat dan internal dan getter melalui atribut [JsonInclude]. Untuk kode sampel, lihat Pengakses properti non-publik.

Mengisi objek yang ada

Metode JsonConvert.PopulateObject dalam Newtonsoft.Json mendeserialisasi dokumen JSON ke instans kelas yang ada, alih-alih membuat instans baru. System.Text.Json selalu membuat instans baru dari jenis target dengan menggunakan konstruktor tanpa parameter publik default. Pengonversi kustom dapat mendeserialisasi ke instans yang ada.

Gunakan kembali daripada mengganti properti

Mulai dari .NET 8, System.Text.Json mendukung penggunaan kembali properti yang diinisialisasi daripada menggantinya. Ada beberapa perbedaan perilaku, yang dapat Anda baca di proposal API.

Untuk informasi selengkapnya, lihat Mengisi properti yang diinisialisasi.

Pengaturan ObjectCreationHandling di Newtonsoft.Json memungkinkan Anda menentukan bahwa objek dalam properti harus digunakan kembali daripada diganti selama deserialisasi. System.Text.Json selalu mengganti objek dalam properti. Pengonversi kustom dapat menyediakan fungsionalitas ini, atau Anda dapat meningkatkan ke .NET 8, yang menyediakan fungsionalitas pengisian.

Mengisi properti tanpa setter

Mulai dari .NET 8, System.Text.Json mendukung pengisian properti, termasuk yang tidak memiliki setter. Untuk informasi selengkapnya, lihat Mengisi properti yang diinisialisasi.

Selama deserialisasi, Newtonsoft.Json menambahkan objek ke koleksi meskipun properti tidak memiliki setter. System.Text.Json mengabaikan properti yang tidak memiliki setter. Pengonversi kustom dapat menyediakan fungsionalitas ini, atau Anda dapat meningkatkan ke .NET 8, yang dapat mengisi properti baca-saja.

Kebijakan penamaan snake case

System.Text.Json termasuk kebijakan penamaan bawaan untuk kasus ular. Namun, ada beberapa perbedaan perilaku dengan Newtonsoft.Json untuk beberapa input. Tabel berikut menunjukkan beberapa perbedaan ini saat mengonversi input menggunakan JsonNamingPolicy.SnakeCaseLower kebijakan.

Input Newtonsoft.Json Hasil System.Text.Json Hasil
"AB1" "a_b1" "ab1"
"SHA512Managed" "sh_a512_managed" "sha512_managed"
"abc123DEF456" "abc123_de_f456" "abc123_def456"
"KEBAB-CASE" "keba_b-_case" "kebab-case"

Satu-satunya kebijakan penamaan properti bawaan adalah System.Text.Json untuk kasus camel. Newtonsoft.Json dapat mengonversi nama properti menjadi snake case. Kebijakan penamaan kustom dapat menyediakan fungsionalitas ini, atau meningkatkan ke .NET 8 atau yang lebih baru, yang mencakup kebijakan penamaan kasus ular bawaan.

Atribut System.Runtime.Serialization

System.Runtime.Serializationatribut seperti DataContractAttribute, , dan IgnoreDataMemberAttribute memungkinkan Anda menentukan kontrak data. DataMemberAttribute Kontrak data adalah perjanjian formal antara layanan dan klien yang secara abstrak menjelaskan data yang akan ditukar. Kontrak data secara tepat menentukan properti mana yang diserialisasikan untuk pertukaran.

System.Text.Json tidak memiliki dukungan bawaan untuk atribut ini. Namun, mulai dari .NET 7, Anda dapat menggunakan pemecah masalah jenis kustom untuk menambahkan dukungan. Untuk sampel, lihat ZCS. DataContractResolver.

Angka oktal

Newtonsoft.Json memperlakukan angka dengan nol di depannya sebagai angka oktal. System.Text.Json tidak mengizinkan nol di depan karena spesifikasi RFC 8259 tidak mengizinkannya.

Menangani anggota yang hilang

Jika JSON yang sedang dideserialisasi menyertakan properti yang hilang dalam jenis target, Newtonsoft.Json dapat dikonfigurasi untuk melemparkan pengecualian. Secara default, System.Text.Json mengabaikan properti tambahan di JSON, kecuali saat Anda menggunakan atribut [JsonExtensionData].

Di .NET 8 dan versi yang lebih baru, Anda dapat mengatur preferensi Anda apakah akan melewati atau melarang properti JSON yang tidak dipetakan menggunakan salah satu cara berikut:

JsonObjectAttribute

Newtonsoft.Json memiliki atribut, JsonObjectAttribute, yang dapat diterapkan pada tingkat jenis untuk mengontrol anggota mana yang diserialisasikan, bagaimana null nilai ditangani, dan apakah semua anggota diperlukan. System.Text.Json tidak memiliki atribut yang setara yang dapat diterapkan pada jenis. Untuk beberapa perilaku, seperti null penanganan nilai, Anda dapat mengonfigurasi perilaku yang sama pada global JsonSerializerOptions atau satu per satu pada setiap properti.

Pertimbangkan contoh berikut yang menggunakan Newtonsoft.Json.JsonObjectAttribute untuk menentukan bahwa semua null properti harus diabaikan:

[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
public class Person { ... }

Di System.Text.Json, Anda dapat mengatur perilaku untuk semua jenis dan properti:

JsonSerializerOptions options = new()
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};

string json = JsonSerializer.Serialize<Person>(person, options);

Atau Anda dapat mengatur perilaku pada setiap properti secara terpisah:

public class Person
{
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Name { get; set; }

    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public int? Age { get; set; }
}

Selanjutnya, pertimbangkan contoh berikut yang menggunakan Newtonsoft.Json.JsonObjectAttribute untuk menentukan bahwa semua properti anggota harus ada di JSON:

[JsonObject(ItemRequired = Required.Always)]
public class Person { ... }

Anda dapat mencapai perilaku yang sama dengan System.Text.Json menambahkan pengubah C# required atau ke JsonRequiredAttributesetiap properti. Untuk informasi selengkapnya, lihat Properti yang diperlukan.

public class Person
{
    [JsonRequired]
    public string? Name { get; set; }

    public required int? Age { get; set; }
}

TraceWriter

Newtonsoft.Json memungkinkan Anda men-debug dengan menggunakan TraceWriter untuk melihat log yang dihasilkan oleh serialisasi atau deserialisasi. System.Text.Json tidak melakukan pengelogan.

JsonDocument dan JsonElement dibandingkan dengan JToken (seperti JObject, JArray)

System.Text.Json.JsonDocument menyediakan kemampuan untuk mengurai dan membangun Model Objek Dokumen (DOM) baca-saja dari payload JSON yang ada. DOM menyediakan akses acak ke data dalam payload JSON. Elemen JSON yang menyusun payload dapat diakses melalui jenis JsonElement. Jenis JsonElement ini menyediakan API untuk mengonversi teks JSON ke jenis .NET umum. JsonDocument mengekspos RootElement properti.

Mulai dari .NET 6, Anda dapat mengurai dan membangun DOM yang dapat diubah dari payload JSON yang ada dengan menggunakan JsonNode jenis dan jenis lain di System.Text.Json.Nodes namespace layanan. Untuk informasi lebih lanjut, lihat Penggunaan JsonNode.

JsonDocument adalah IDisposable

JsonDocument membuat tampilan data dalam memori ke dalam buffer yang dikumpulkan. Oleh karena itu, tidak seperti JObject atau JArray dari Newtonsoft.Json, jenis JsonDocument mengimplementasikan IDisposable dan perlu digunakan di dalam blok penggunaan. Untuk informasi selengkapnya, lihat JsonDocument adalah IDisposable.

JsonDocument bersifat baca-saja

System.Text.Json DOM tidak dapat menambahkan, menghapus, atau memodifikasi elemen JSON. Dirancang seperti ini untuk performa dan untuk mengurangi alokasi demi menguraikan ukuran payload JSON umum (yaitu, < 1 MB).

JsonElement adalah struktur perpaduan

JsonDocument mengekspos RootElement sebagai properti jenis JsonElement, yang merupakan jenis struktur gabungan yang mencakup elemen JSON apa pun. Newtonsoft.Json menggunakan jenis hierarki khusus seperti JObject,JArray, JToken, dan sebagainya. JsonElement adalah apa yang dapat Anda cari dan hitung, dan Anda dapat menggunakan JsonElement untuk mewujudkan elemen JSON ke dalam jenis .NET.

Mulai dari .NET 6, Anda dapat menggunakan JsonNode jenis dan jenis di System.Text.Json.Nodes namespace layanan yang sesuai dengan JObject,JArray , dan JToken. Untuk informasi lebih lanjut, lihat Penggunaan JsonNode.

Cara mencari JsonDocument dan JsonElement untuk subelemen

Pencarian token JSON menggunakan JObject atau JArray dari Newtonsoft.Json cenderung relatif cepat karena mereka mencari dari beberapa kamus. Sebagai perbandingan, pencarian pada JsonElement memerlukan pencarian properti secara berurutan dan membuatnya menjadi relatif lambat (misalnya saat menggunakan TryGetProperty). System.Text.Json dirancang untuk meminimalkan waktu penguraian awal daripada waktu pencarian. Untuk informasi tentang DOM, lihat Cara mencari JsonDocument dan JsonElement untuk sub-elemen.

Utf8JsonReader vs. JsonTextReader

System.Text.Json.Utf8JsonReaderadalah pembaca berkinerja tinggi, beralokasi rendah, pembaca terusan untuk teks JSON yang dikodekan oleh UTF-8, baca dari ReadOnlySpan<byte> atau ReadOnlySequence<byte>. Utf8JsonReader adalah jenis tingkat rendah yang dapat digunakan untuk membuat pengurai dan deserializer khusus.

Utf8JsonReader adalah struktur ref

JsonTextReader padai Newtonsoft.Json adalah sebuah kelas. Jenis Utf8JsonReader berbeda karena ini adalah struktur ref. Untuk informasi selengkapnya, lihat batasan struktur ref untuk Utf8JsonReader.

Membaca nilai null ke dalam jenis nilai nullable

Newtonsoft.Jsonmenyediakan API yang mengembalikan Nullable<T>, seperti ReadAsBoolean, yang menangani NullTokenType untuk Anda dengan mengembalikan bool?. API System.Text.Json bawaan hanya mengembalikan jenis nilai yang tidak dapat diubah ke null. Untuk informasi selengkapnya, lihat Membaca nilai null ke dalam jenis nilai null.

Multi-target untuk membaca JSON

Jika Anda perlu terus menggunakan Newtonsoft.Json untuk kerangka kerja target tertentu, Anda dapat melakukan multi-target dan memiliki dua implementasi. Namun, ini tidak sepele dan akan membutuhkan beberapa #ifdefs dan duplikasi sumber. Salah satu cara untuk berbagi kode sebanyak mungkin adalah dengan membuat ref struct pembungkus di sekitar Utf8JsonReader dan Newtonsoft.Json.JsonTextReader. Pembungkus ini akan menyatukan area permukaan publik sambil mengisolasi perbedaan perilaku. Ini memungkinkan Anda mengisolasi perubahan terutama pada konstruksi jenis, bersamaan dengan melewati jenis baru berdasarkan referensi. Ini adalah pola yang diikuti oleh pustaka Microsoft.Extensions.DependencyModel:

Utf8JsonWriter vs. JsonTextWriter

System.Text.Json.Utf8JsonWriter adalah cara beperforma tinggi untuk menulis teks JSON yang dikodekan UTF-8 dari jenis .NET umum seperti String, Int32, dan DateTime. Penulis adalah jenis tingkat rendah yang dapat digunakan untuk membangun serializer kustom.

Menulis nilai mentah

Newtonsoft.Json memiliki WriteRawValue metode yang menulis JSON mentah di mana nilai diharapkan. System.Text.Json memiliki persamaan langsung: Utf8JsonWriter.WriteRawValue. Untuk informasi selengkapnya, lihat Menulis JSON mentah.

Mengkustomisasi format JSON

JsonTextWriter termasuk pengaturan berikut, di mana Utf8JsonWriter tidak memiliki persamaan:

  • QuoteChar - Menentukan karakter yang akan digunakan untuk mengelilingi nilai string. Utf8JsonWriter selalu menggunakan tanda kutip ganda.
  • QuoteName - Menentukan apakah akan mengelilingi nama properti dengan tanda kutip atau tidak. Utf8JsonWriter selalu mengelilinginya dengan tanda kutip.

Mulai dari .NET 9, Anda dapat menyesuaikan karakter dan ukuran indentasi untuk Utf8JsonWriter menggunakan opsi yang JsonWriterOptions diekspos oleh struktur:

  • JsonWriterOptions.IndentCharacter
  • JsonWriterOptions.IndentSize

JsonTextWriter termasuk pengaturan berikut, di mana Utf8JsonWriter tidak memiliki persamaan:

  • Indentasi - Menentukan berapa banyak karakter yang akan diindentasi. Utf8JsonWriter selalu inden sebesar 2 karakter.
  • IndentChar - Menentukan karakter yang akan digunakan untuk indentasi. Utf8JsonWriter selalu menggunakan spasi kosong.
  • QuoteChar - Menentukan karakter yang akan digunakan untuk mengelilingi nilai string. Utf8JsonWriter selalu menggunakan tanda kutip ganda.
  • QuoteName - Menentukan apakah akan mengelilingi nama properti dengan tanda kutip atau tidak. Utf8JsonWriter selalu mengelilinginya dengan tanda kutip.

Tidak ada solusi yang memungkinkan Anda menyesuaikan JSON yang dihasilkan Utf8JsonWriter dengan cara ini.

Menulis nilai Rentang Waktu, Uri, atau nilai char

JsonTextWriter menyediakan WriteValue metode untuk TimeSpan, Uri, dan nilai karakter. Utf8JsonWriter tidak memiliki metode yang setara. Sebagai gantinya, formatlah nilai-nilai ini sebagai string (dengan memanggil ToString(), misalnya) dan panggil WriteStringValue.

Multi-target untuk menulis JSON

Jika Anda perlu terus menggunakan Newtonsoft.Json untuk kerangka kerja target tertentu, Anda dapat melakukan multi-target dan memiliki dua implementasi. Namun, ini tidak sepele dan akan membutuhkan beberapa #ifdefs dan duplikasi sumber. Salah satu cara untuk berbagi kode sebanyak mungkin adalah dengan membuat pembungkus di sekitar Utf8JsonWriterdan Newtonsoft.Json.JsonTextWriter. Pembungkus ini akan menyatukan area permukaan publik sambil mengisolasi perbedaan perilaku. Ini memungkinkan Anda mengisolasi perubahan terutama pada konstruksi jenis. Pustaka Microsoft.Extensions.DependencyModel mengikuti:

TypeNameHandling.All tidak didukung

Keputusan untuk mengecualikan fungsionalitas setara TypeNameHandling.All dari System.Text.Json dilakukan dengan sengaja. Mengizinkan payload JSON untuk menentukan informasi jenisnya sendiri adalah sumber kerentanan umum dalam aplikasi web. Secara khusus, mengonfigurasi Newtonsoft.Json dengan TypeNameHandling.All memungkinkan klien jarak jauh untuk menyematkan seluruh aplikasi yang dapat dieksekusi dalam payload JSON itu sendiri, sehingga selama deserialisasi, aplikasi web mengekstrak dan menjalankan kode yang disematkan. Untuk informasi selengkapnya, lihat PowerPoint serangan JSON pada Jumat tanggal 13 dan detail serangan JSON pada Jumat tanggal 13.

Kueri Jalur JSON tidak didukung

DOM JsonDocument tidak mendukung kueri dengan menggunakan JSON Path.

Pada DOM JsonNode, setiap JsonNode instans memiliki GetPath metode yang mengembalikan jalur ke simpul tersebut. Tetapi tidak ada API bawaan untuk menangani kueri berdasarkan string kueri JSON Path.

Untuk informasi selengkapnya, lihat masalah GitHub dotnet/runtime #31068.

Beberapa batasan tidak dapat dikonfigurasi

System.Text.Json menetapkan batas yang tidak dapat diubah untuk beberapa nilai, seperti ukuran token maksimum dalam karakter (166 MB) dan dalam basis 64 (125 MB). Untuk informasi selengkapnya, lihat JsonConstants pada kode sumber dan masalah GitHub dotnet/runtime #39953.

Nan, Infinity, -Infinity

Newtonsoft mengurai token string JSON NaN, Infinity, dan -Infinity. Dengan System.Text.Json, gunakan JsonNumberHandling.AllowNamedFloatingPointLiterals. Untuk informasi tentang cara menggunakan pengaturan ini, lihat Mengizinkan atau menulis angka dalam tanda kutip.

Sumber Daya Tambahan: