Cara mengecualikan properti dari Json Serialization

235

Saya memiliki kelas DTO yang saya serialkan

Json.Serialize(MyClass)

Bagaimana saya bisa mengecualikan properti publik itu?

(Itu harus bersifat publik, karena saya menggunakannya dalam kode saya di tempat lain)

Elad Benda
sumber
4
Kerangka kerja serialisasi mana yang Anda gunakan?
Pavel Gatilov
37
IgnoreDataMember ScriptIgnore JsonIgnoretergantung pada serializer yang Anda gunakan
LB
3
juga patut diperhatikan adalah atribut [NonSerialized], yang hanya berlaku untuk bidang (bukan properti), tetapi sebaliknya memiliki efek yang sama dengan JsonIgnore.
Triynko
Komentar Trynko sangat berguna .... jika Anda menggunakan IgnoreDataMember pada bidang tidak akan ada kesalahan, tetapi itu tidak akan diterapkan.
Tillito

Jawaban:

147

Jika Anda menggunakan System.Web.Script.Serializationdalam kerangka NET. Anda dapat menempatkan ScriptIgnoreatribut pada anggota yang tidak boleh serial. Lihat contoh yang diambil dari sini :

Pertimbangkan kasus berikut (disederhanakan):

public class User {
    public int Id { get; set; }
    public string Name { get; set; }
    [ScriptIgnore]
    public bool IsComplete
    {
        get { return Id > 0 && !string.IsNullOrEmpty(Name); }
    } 
} 

Dalam kasus ini, hanya properti Id dan Name yang akan diserialisasi, sehingga objek JSON yang dihasilkan akan terlihat seperti ini:

{ Id: 3, Name: 'Test User' }

PS. Jangan lupa menambahkan referensi ke " System.Web.Extensions" agar ini berfungsi

Pavel Krymets
sumber
10
Saya temukan ScriptIgnoredi System.Web.Script.Serializationnamespace.
Sorangwala Abbasali
354

Jika Anda menggunakan atribut Json.Net[JsonIgnore] hanya akan mengabaikan bidang / properti saat membuat serial atau deserialising.

public class Car
{
  // included in JSON
  public string Model { get; set; }
  public DateTime Year { get; set; }
  public List<string> Features { get; set; }

  // ignored
  [JsonIgnore]
  public DateTime LastModified { get; set; }
}

Atau Anda dapat menggunakan atribut DataContract dan DataMember untuk membuat serialisasi / deserialize properti / bidang secara selektif.

[DataContract]
public class Computer
{
  // included in JSON
  [DataMember]
  public string Name { get; set; }
  [DataMember]
  public decimal SalePrice { get; set; }

  // ignored
  public string Manufacture { get; set; }
  public int StockCount { get; set; }
  public decimal WholeSalePrice { get; set; }
  public DateTime NextShipmentDate { get; set; }
}

Rujuk http://james.newtonking.com/archive/2009/10/23/efisien-json-with-json-net-reducing-serialized-json-size untuk detail lebih lanjut

JC Raja
sumber
37
Jika saya OP, saya lebih suka jawaban ini daripada solusi [ScriptIgnore] yang dipilih. Terutama karena kongruensi solusi Json jadi masalah Json. Mengapa melibatkan System.Web.Extensions ketika perpustakaan yang Anda gunakan memberikan solusi? IMHO terbaik mutlak adalah atribut [IgnoreDataMember], sebagai System.Runtime.Serialization harus kompatibel dengan setiap serializer jika Anda ingin menukar Json.
Steve H.
IgnoreDataMembertidak bekerja dengan JsonResultserializer default .
hendryanw
1
NewtonSoft hanya membantu saya sepenuhnya. Itu membuat json saya terlihat bersih tanpa ada sifat berantakan yang disertakan dari model saya yang hanya untuk backend.
Sorangwala Abbasali
1
@JC Raja Bagaimana saya bisa mengabaikan properti selama desalinizing hanya ketika properti ini null
user123456
1
[NewtonSoft.Json] Saya ingin mengabaikan serialisasi saja. Lalu ada solusi untuk ini?
Trống Quốc Khánh
31

Anda bisa menggunakan [ScriptIgnore]:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    [ScriptIgnore]
    public bool IsComplete
    {
        get { return Id > 0 && !string.IsNullOrEmpty(Name); }
    }
}

Referensi di sini

Dalam hal ini Id dan nama hanya akan diserialisasi

Arion
sumber
1
URL dalam jawaban Anda rusak. Apakah [ScriptIgnore]yang harus digunakan di properti jika controller Anda menggunakan basis MVC Controller return Json(...?
Don Cheadle
2
Saya tahu ini adalah komentar lama, tapi ya, gunakan [ScriptIgnore]di MVC Controller. Namun berhati-hatilah, jika Anda menggunakan SignalR , maka Anda juga harus menggunakannya [JsonIgnore].
Sam
22

Maaf saya memutuskan untuk menulis jawaban lain karena tidak ada jawaban lain yang cukup bisa di-paste.

Jika Anda tidak ingin menghiasi properti dengan beberapa atribut, atau jika Anda tidak memiliki akses ke kelas, atau jika Anda ingin memutuskan apa yang akan diserialisasi selama runtime, dll. Inilah cara Anda melakukannya di Newtonsoft.Json

//short helper class to ignore some properties from serialization
public class IgnorePropertiesResolver : DefaultContractResolver
{
    private IEnumerable<string> _propsToIgnore;
    public IgnorePropertiesResolver(IEnumerable<string> propNamesToIgnore)
    {
        _propsToIgnore = propNamesToIgnore;
    }
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        property.ShouldSerialize = (x) => { return !_propsToIgnore.Contains(property.PropertyName); };
        return property;
    }
}

Pemakaian

JsonConvert.SerializeObject(YourObject, new JsonSerializerSettings()
    { ContractResolver = new IgnorePropertiesResolver(new[] { "Prop1", "Prop2" }) };);

Saya telah menerbitkan kode di sini kalau-kalau ada yang ingin menambahkan sesuatu

https://github.com/jitbit/JsonIgnoreProps

PEMBARUAN PENTING: pastikan Anda men-cache ContractResolverobjek jika Anda memutuskan untuk menggunakan jawaban ini, jika tidak kinerjanya akan menurun.

Alex
sumber
15

Jika Anda tidak begitu tertarik untuk harus menghias kode dengan Atribut seperti saya, terutama ketika Anda tidak bisa mengatakan pada waktu kompilasi apa yang akan terjadi di sini adalah solusi saya.

Menggunakan Javascript Serializer

    public static class JsonSerializerExtensions
    {
        public static string ToJsonString(this object target,bool ignoreNulls = true)
        {
            var javaScriptSerializer = new JavaScriptSerializer();
            if(ignoreNulls)
            {
                javaScriptSerializer.RegisterConverters(new[] { new PropertyExclusionConverter(target.GetType(), true) });
            }
            return javaScriptSerializer.Serialize(target);
        }

        public static string ToJsonString(this object target, Dictionary<Type, List<string>> ignore, bool ignoreNulls = true)
        {
            var javaScriptSerializer = new JavaScriptSerializer();
            foreach (var key in ignore.Keys)
            {
                javaScriptSerializer.RegisterConverters(new[] { new PropertyExclusionConverter(key, ignore[key], ignoreNulls) });
            }
            return javaScriptSerializer.Serialize(target);
        }
    }


public class PropertyExclusionConverter : JavaScriptConverter
    {
        private readonly List<string> propertiesToIgnore;
        private readonly Type type;
        private readonly bool ignoreNulls;

        public PropertyExclusionConverter(Type type, List<string> propertiesToIgnore, bool ignoreNulls)
        {
            this.ignoreNulls = ignoreNulls;
            this.type = type;
            this.propertiesToIgnore = propertiesToIgnore ?? new List<string>();
        }

        public PropertyExclusionConverter(Type type, bool ignoreNulls)
            : this(type, null, ignoreNulls){}

        public override IEnumerable<Type> SupportedTypes
        {
            get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { this.type })); }
        }

        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var result = new Dictionary<string, object>();
            if (obj == null)
            {
                return result;
            }
            var properties = obj.GetType().GetProperties();
            foreach (var propertyInfo in properties)
            {
                if (!this.propertiesToIgnore.Contains(propertyInfo.Name))
                {
                    if(this.ignoreNulls && propertyInfo.GetValue(obj, null) == null)
                    {
                         continue;
                    }
                    result.Add(propertyInfo.Name, propertyInfo.GetValue(obj, null));
                }
            }
            return result;
        }

        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
            throw new NotImplementedException(); //Converter is currently only used for ignoring properties on serialization
        }
    }
Thulani Chivandikwa
sumber
1
Perubahan kecil dalam logika dan PropertyExclusionConverterdapat diubah menjadi PropertyInclusionConverter.
Zarepheth
ini luar biasa
SaiKiran Mandhala
Salah satu masalah potensial dengan ini adalah bahwa ia harus melakukan pencocokan nama dan pengecualian kerja setiap kali objek serial. Namun, setelah dikompilasi, properti tipe tidak akan berubah - Anda harus membuat ini pra-kalkulasi, per jenis, nama-nama yang harus dimasukkan dan hanya menggunakan kembali daftar di setiap baris. Untuk pekerjaan serialisasi JSON yang sangat masif, caching dapat membuat perbedaan nyata dalam kinerja.
ErikE
9

Jika Anda menggunakan System.Text.Jsonmaka Anda dapat menggunakan [JsonIgnore].
FQ:System.Text.Json.Serialization.JsonIgnoreAttribute

Microsoft Documents Resmi: JsonIgnoreAttribute

Seperti yang dinyatakan di sini :

Perpustakaan dibangun sebagai bagian dari kerangka kerja bersama .NET Core 3.0.
Untuk kerangka kerja target lainnya, instal paket System.Text.Json NuGet. Paket ini mendukung:

  • .NET Standard 2.0 dan versi yang lebih baru
  • .NET Framework 4.6.1 dan versi yang lebih baru
  • .NET Core 2.0, 2.1, dan 2.2
Travis
sumber
0

Anda juga dapat menggunakan [NonSerialized]atribut

[Serializable]
public struct MySerializableStruct
{
    [NonSerialized]
    public string hiddenField;
    public string normalField;
}

Dari dokumen MS :

Menunjukkan bahwa bidang kelas serial harus tidak diserialisasi. Kelas ini tidak dapat diwarisi.


Jika Anda menggunakan Unity misalnya ( ini bukan hanya untuk Unity ) maka ini berfungsi dengan baikUnityEngine.JsonUtility

using UnityEngine;

MySerializableStruct mss = new MySerializableStruct 
{ 
    hiddenField = "foo", 
    normalField = "bar" 
};
Debug.Log(JsonUtility.ToJson(mss)); // result: {"normalField":"bar"}
Ya Barry
sumber