Cara mengabaikan properti di kelas jika null, menggunakan json.net

529

Saya menggunakan Json.NET untuk membuat cerita bersambung suatu kelas menjadi JSON.

Saya memiliki kelas seperti ini:

class Test1
{
    [JsonProperty("id")]
    public string ID { get; set; }
    [JsonProperty("label")]
    public string Label { get; set; }
    [JsonProperty("url")]
    public string URL { get; set; }
    [JsonProperty("item")]
    public List<Test2> Test2List { get; set; }
}

Saya ingin menambahkan JsonIgnore()atribut ke Test2Listproperti hanya jika Test2Listada null. Jika tidak nol maka saya ingin memasukkannya di json saya.

Amit
sumber

Jawaban:

685

Sesuai James Newton King: Jika Anda membuat serializer sendiri daripada menggunakan JavaScriptConvert, ada NullValueHandlingproperti yang bisa Anda atur untuk diabaikan.

Berikut ini contohnya:

JsonSerializer _jsonWriter = new JsonSerializer {
                                 NullValueHandling = NullValueHandling.Ignore
                             };

Atau, seperti yang disarankan oleh @amit

JsonConvert.SerializeObject(myObject, 
                            Newtonsoft.Json.Formatting.None, 
                            new JsonSerializerSettings { 
                                NullValueHandling = NullValueHandling.Ignore
                            });
Tuan
sumber
159
Ini berfungsi: JsonConvert.SerializeObject (myObject, Newtonsoft.Json.Formatting.None, JsonSerializerSettings baru {NullValueHandling = NullValueHandling.Ignore});
Amit
itu bekerja untuk saya tetapi saya harus menggunakan JsonSerializerSettingstidak JsonSerializerkarena itu menunjukkan kesalahan untuk yang terakhir
Yazan
1
satu hal penting - ini hanya berfungsi dengan kelas konkret (Orang, Akun, dll.). ketika saya mencoba ini dengan Kamus, itu tidak berhasil
chester89
1
Saya memiliki masalah yang sama dengan @ chester89. Dengan nilai null ExpandoObject tidak diabaikan. Itu tampaknya menjadi bug (menggunakan json.net 9.0.1)
kwrl
2
Ketika jawabannya ditulis, JSON.Net bahkan tidak mendukung objek dinamis. :) Saat ini, Anda dapat menggunakan konverter khusus untuk melakukan penawaran Anda.
Mrchief
923

Solusi alternatif menggunakan JsonPropertyatribut:

[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
// or
[JsonProperty("property_name", NullValueHandling=NullValueHandling.Ignore)]

// or for all properties in a class
[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]

Seperti yang terlihat dalam dokumen online ini .

sirthomas
sumber
19
Jawaban yang diterima lebih baik karena tidak mencemari kelas Anda dengan atribut Json.net.
Sergey
117
@ Tampaknya tergantung pada kasus penggunaan Anda. Jika Anda hanya ingin memilikinya untuk properti tertentu (seperti yang disebutkan dalam pertanyaan), maka ini adalah jawaban yang benar. Jika Anda menginginkan jawaban global, Anda harus mengatur properti di JsonSerializer.
sibbl
Setuju - ini sederhana dan elegan. Layak upvoting. Berfungsi bagus - cukup tetapkan properti di objek yang ingin Anda serialkan ke Nothing in VB dan itu bukan lagi bagian dari JSON. Ini hanya akan bekerja dengan Strings. Properti yang enum atau bilangan bulat akan selalu muncul - pengaturan ke Nothing menghasilkan nilai default "0".
Destek
3
@Destek Anda perlu membuat bidang jenis referensi dapat dibatalkan, maka mereka tidak akan diserialisasi menggunakan atribut atau pengaturan.
Tony
1
Untuk menghindari 'mencemari' kelas Anda dengan banyak atribut, Anda juga dapat menetapkan aturan penanganan [JsonObject], tetapi perhatikan bahwa nama atribut berbeda. [jawaban yang diedit]
Simon_Weaver
60

Mirip dengan jawaban @ sirthomas ini, JSON.NET juga menghormati para EmitDefaultValueproperti di DataMemberAttribute:

[DataMember(Name="property_name", EmitDefaultValue=false)]

Ini mungkin diinginkan jika Anda sudah menggunakan [DataContract]dan [DataMember]dalam tipe model Anda dan tidak ingin menambahkan atribut JSON.NET-spesifik.

Tobias J
sumber
1
Ini sangat membantu! Saya sedang merancang kelas pengecualian khusus dan saya tidak ingin menambahkan hal-hal Json.net di sana. Terima kasih!
jpgrassi
2
Ini tidak berfungsi di .Net Core. Recomend @sirthomas jawab: gunakan [JsonProperty (NullValueHandling = NullValueHandling.Ignore)]
Derrick
1
Ini berfungsi dengan baik untuk saya di. Net Core dengan Newtonsoft.Json 10.0.2.
Karl-Johan Sjögren
33

Kamu bisa menulis: [JsonProperty("property_name",DefaultValueHandling = DefaultValueHandling.Ignore)]

Ini juga menangani tidak membuat serialisasi properti dengan nilai default (tidak hanya nol). Ini bisa bermanfaat untuk enum misalnya.

Vatsal Patel
sumber
3
Ini persis sama dengan jawaban sirthomas, mengapa Anda menambahkannya?
OMGtechy
4
Untuk informasi Anda yang baik, ada perbedaan antara DefaultValueHandling dan NullValueHandling ...
Vatsal Patel
4
Bisakah Anda menjelaskannya dalam jawaban Anda? Pada pandangan pertama, tampilannya sama, dan sekarang Anda telah menyebutkannya, itu tidak menyatakan bagaimana ini berbeda dari jawaban yang lain / bagaimana pujian itu dipuji.
OMGtechy
1
Meskipun jawaban yang diterima mungkin berguna dalam beberapa keadaan, tidak selalu memungkinkan untuk menggunakannya. Ini hanya apa yang diperintahkan dokter.
Pengembang Melbourne
1
Saya pikir inilah yang saya inginkan. Penanganan khusus pada properti tertentu, tidak semua.
frostymarvelous
23

Anda bisa melakukan ini untuk mengabaikan semua null di objek yang Anda serialkan, dan properti null apa pun tidak akan muncul di JSON

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
var myJson = JsonConvert.SerializeObject(myObject, settings);
Chris Halcrow
sumber
12

Seperti yang dapat dilihat di tautan ini di situs mereka (http://james.newtonking.com/archive/2009/10/23/efisien-json-with-json-net-netucing-serialized-json-size.aspx) I dukungan menggunakan [Default ()] untuk menentukan nilai default

Diambil dari tautan

   public class Invoice
{
  public string Company { get; set; }
  public decimal Amount { get; set; }

  // false is default value of bool
  public bool Paid { get; set; }
  // null is default value of nullable
  public DateTime? PaidDate { get; set; }

  // customize default values
  [DefaultValue(30)]
  public int FollowUpDays { get; set; }
  [DefaultValue("")]
  public string FollowUpEmailAddress { get; set; }
}


Invoice invoice = new Invoice
{
  Company = "Acme Ltd.",
  Amount = 50.0m,
  Paid = false,
  FollowUpDays = 30,
  FollowUpEmailAddress = string.Empty,
  PaidDate = null
};

string included = JsonConvert.SerializeObject(invoice,
  Formatting.Indented,
  new JsonSerializerSettings { });

// {
//   "Company": "Acme Ltd.",
//   "Amount": 50.0,
//   "Paid": false,
//   "PaidDate": null,
//   "FollowUpDays": 30,
//   "FollowUpEmailAddress": ""
// }

string ignored = JsonConvert.SerializeObject(invoice,
  Formatting.Indented,
  new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });

// {
//   "Company": "Acme Ltd.",
//   "Amount": 50.0
// }
Mickey Perlstein
sumber
3

Di .Net Core ini jauh lebih mudah sekarang. Di startup.cs Anda cukup tambahkan opsi json dan Anda dapat mengonfigurasi pengaturan di sana.


public void ConfigureServices(IServiceCollection services)

....

services.AddMvc().AddJsonOptions(options =>
{
   options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;               
});
Hizzy
sumber
1

Dengan Json.NET

 public class Movie
 {
            public string Name { get; set; }
            public string Description { get; set; }
            public string Classification { get; set; }
            public string Studio { get; set; }
            public DateTime? ReleaseDate { get; set; }
            public List<string> ReleaseCountries { get; set; }
 }

 Movie movie = new Movie();
 movie.Name = "Bad Boys III";
 movie.Description = "It's no Bad Boys";

 string ignored = JsonConvert.SerializeObject(movie,
            Formatting.Indented,
            new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });

Hasilnya adalah:

{
   "Name": "Bad Boys III",
   "Description": "It's no Bad Boys"
 }
Rafy
sumber
1

Dengan System.Text.Jsondan .NET Core 3.0 ini berfungsi untuk saya:

var jsonSerializerOptions = new JsonSerializerOptions()
{
    IgnoreNullValues = true
};
var myJson = JsonSerializer.Serialize(myObject, jsonSerializerOptions );
Pascal R.
sumber
0

Untuk sedikit menguraikan jawaban GlennG yang sangat membantu (menerjemahkan sintaks dari C # ke VB.Net tidak selalu "jelas"), Anda juga dapat menghiasi properti kelas individu untuk mengelola bagaimana nilai-nilai nol ditangani. Jika Anda melakukan ini jangan gunakan global JsonSerializerSettings dari saran GlennG, jika tidak maka akan menimpa dekorasi individu. Ini sangat berguna jika Anda ingin item nol muncul di JSON sehingga konsumen tidak perlu melakukan penanganan khusus. Jika, misalnya, konsumen perlu mengetahui berbagai item opsional biasanya tersedia, tetapi saat ini kosong ... Dekorasi dalam deklarasi properti terlihat seperti ini:

<JsonPropertyAttribute("MyProperty", DefaultValueHandling:=NullValueHandling.Include)> Public Property MyProperty As New List(of String)

Untuk properti yang Anda tidak ingin muncul sama sekali dalam perubahan JSON : = NullValueHandling.Termasuk ke : = NullValueHandling.Ignore . Ngomong-ngomong - Saya telah menemukan bahwa Anda dapat menghiasi properti untuk serialisasi XML dan JSON dengan baik (cukup letakkan di samping satu sama lain). Ini memberi saya pilihan untuk memanggil serializer XML di dotnet atau serializer NewtonSoft sesuka hati - keduanya bekerja berdampingan dan pelanggan saya memiliki opsi untuk bekerja dengan XML atau JSON. Ini licin karena ingus pada gagang pintu karena saya memiliki pelanggan yang membutuhkan keduanya!

Destek
sumber
0

Berikut ini opsi yang serupa, tetapi memberikan pilihan lain:

public class DefaultJsonSerializer : JsonSerializerSettings
{
    public DefaultJsonSerializer()
    {
        NullValueHandling = NullValueHandling.Ignore;
    }
}

Lalu, saya menggunakannya seperti ini:

JsonConvert.SerializeObject(postObj, new DefaultJsonSerializer());

Perbedaannya di sini adalah:

  • Mengurangi kode berulang dengan membuat instance dan mengkonfigurasi JsonSerializerSettingssetiap tempat yang digunakan.
  • Menghemat waktu dalam mengonfigurasi setiap properti dari setiap objek yang akan diserialisasi.
  • Masih memberi pengembang lain fleksibilitas dalam opsi serialisasi, daripada memiliki properti yang secara eksplisit ditentukan pada objek yang dapat digunakan kembali.
  • Kasus penggunaan saya adalah bahwa kode tersebut adalah pustaka pihak ke-3 dan saya tidak ingin memaksakan opsi serialisasi pada pengembang yang ingin menggunakan kembali kelas saya.
  • Kelemahan potensial adalah objek lain yang perlu diketahui pengembang lain, atau jika aplikasi Anda kecil dan pendekatan ini tidak masalah untuk serialisasi tunggal.
Joe Mayo
sumber
-1
var settings = new JsonSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
settings.NullValueHandling = NullValueHandling.Ignore;
//you can add multiple settings and then use it
var bodyAsJson = JsonConvert.SerializeObject(body, Formatting.Indented, settings);
Suresh Bhandari
sumber
settings.NullValueHandling = NullValueHandling.Ignore disarankan untuk jawaban lain. Tidak jelas, apa yang baru dalam jawaban Anda
Michael Freidgeim