So schließen Sie Eigenschaften von der Json-Serialisierung aus

234

Ich habe eine DTO-Klasse, die ich serialisiere

Json.Serialize(MyClass)

Wie kann ich ein öffentliches Eigentum davon ausschließen?

(Es muss öffentlich sein, da ich es in meinem Code woanders verwende.)

Elad Benda
quelle
4
Welches Serialisierungsframework verwenden Sie?
Pavel Gatilov
37
IgnoreDataMember ScriptIgnore JsonIgnoreabhängig von dem Serializer, den Sie verwenden
LB
3
Bemerkenswert ist auch das Attribut [NonSerialized], das nur für Felder (keine Eigenschaften) gilt, ansonsten aber den gleichen Effekt wie JsonIgnore hat.
Triynko
Der Kommentar von Trynko ist sehr nützlich. Wenn Sie IgnoreDataMember für ein Feld verwenden, wird kein Fehler angezeigt, aber er wird nicht angewendet.
Tillito

Antworten:

147

Wenn Sie System.Web.Script.Serializationin .NET Framework verwenden , können Sie ScriptIgnoreden Mitgliedern ein Attribut zuweisen, das nicht serialisiert werden soll. Siehe das Beispiel von hier :

Betrachten Sie den folgenden (vereinfachten) Fall:

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

In diesem Fall werden nur die Eigenschaften Id und Name serialisiert, sodass das resultierende JSON-Objekt folgendermaßen aussehen würde:

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

PS. Vergessen Sie nicht, einen Verweis auf " System.Web.Extensions" hinzuzufügen, damit dies funktioniert

Pavel Krymets
quelle
10
Ich habe ScriptIgnoreim System.Web.Script.SerializationNamespace gefunden.
Sorangwala Abbasali
354

Wenn Sie das Json.Net- Attribut verwenden, [JsonIgnore]wird das Feld / die Eigenschaft beim Serialisieren oder Deserialisieren einfach ignoriert.

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

Sie können auch die Attribute DataContract und DataMember verwenden, um Eigenschaften / Felder selektiv zu serialisieren / deserialisieren.

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

Weitere Informationen finden Sie unter http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size

JC Raja
quelle
37
Wenn ich der OP wäre, würde ich diese Antwort der gewählten [ScriptIgnore] -Lösung vorziehen. In erster Linie aufgrund der Kongruenz einer Json-Lösung also ein Json-Problem. Warum System.Web.Extensions einbeziehen, wenn die von Ihnen verwendete Bibliothek eine Lösung bietet? Das absolut beste IMHO ist das Attribut [IgnoreDataMember], da System.Runtime.Serialization mit jedem Serializer kompatibel sein sollte, falls Sie Json austauschen möchten.
Steve H.
IgnoreDataMemberfunktioniert nicht mit dem Standard- JsonResultSerializer.
Hendryanw
1
NewtonSoft hat mir nur voll geholfen. Dadurch sah mein JSON sauber aus, ohne dass meine Modelle, die nur für das Backend gedacht sind, unordentliche Eigenschaften aufwiesen.
Sorangwala Abbasali
1
@ JC Raja Wie kann ich Eigenschaft während der Entsalzung nur ignorieren, wenn diese Eigenschaft null ist
user123456
1
[NewtonSoft.Json] Ich möchte nur die Serialisierung ignorieren. Dann eine Lösung dafür?
Trương Quốc Khánh
31

Sie können verwenden [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); }
    }
}

Referenz hier

In diesem Fall werden die ID und dann der Name nur serialisiert

Arion
quelle
1
Die URL in Ihrer Antwort ist fehlerhaft. Ist [ScriptIgnore]was soll auf dem Grundstück verwendet werden , wenn der Controller die Basis MVC - Controller verwendet return Json(...?
Don Cheadle
2
Ich weiß, dass es ein alter Kommentar ist, aber ja, [ScriptIgnore]in MVC Controller verwenden. Seien Sie jedoch gewarnt, wenn Sie SignalR verwenden , sollten Sie auch verwenden [JsonIgnore].
Sam
21

Entschuldigung, ich habe beschlossen, eine andere Antwort zu schreiben, da keine der anderen Antworten kopierfähig genug ist.

Wenn Sie Eigenschaften nicht mit einigen Attributen dekorieren möchten oder wenn Sie keinen Zugriff auf die Klasse haben oder wenn Sie entscheiden möchten, was zur Laufzeit serialisiert werden soll, usw. usw., gehen Sie wie folgt in Newtonsoft.Json vor

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

Verwendung

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

Ich habe den Code hier veröffentlicht, falls jemand etwas hinzufügen möchte

https://github.com/jitbit/JsonIgnoreProps

WICHTIGES UPDATE: Stellen Sie sicher, dass Sie das ContractResolverObjekt zwischenspeichern, wenn Sie diese Antwort verwenden. Andernfalls kann die Leistung beeinträchtigt werden.

Alex
quelle
15

Wenn Sie nicht so sehr daran interessiert sind, Code mit Attributen zu dekorieren wie ich, ist es meine Lösung, wenn Sie zum Zeitpunkt der Kompilierung nicht sagen können, was hier passieren wird.

Verwenden des 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
quelle
1
Eine geringfügige Änderung in der Logik und der PropertyExclusionConverterkann in eine umgewandelt werden PropertyInclusionConverter.
Zarepheth
Das ist einfach großartig
SaiKiran Mandhala
Ein mögliches Problem dabei ist, dass die Namensübereinstimmung und der Ausschluss jedes Mal wiederholt werden müssen, wenn ein Objekt serialisiert wird. Nach dem Kompilieren ändern sich die Eigenschaften eines Typs jedoch nicht. Sie sollten die Namen, die enthalten sein sollen, pro Typ vorberechnen und die Liste in jeder Zeile einfach wiederverwenden. Bei einem sehr umfangreichen JSON-Serialisierungsjob kann das Caching einen spürbaren Leistungsunterschied bewirken.
ErikE
9

Wenn Sie verwenden System.Text.Json, können Sie verwenden [JsonIgnore].
FQ:System.Text.Json.Serialization.JsonIgnoreAttribute

Offizielle Microsoft- Dokumente : JsonIgnoreAttribute

Wie hier angegeben :

Die Bibliothek ist als Teil des gemeinsam genutzten .NET Core 3.0-Frameworks integriert.
Installieren Sie für andere Zielframeworks das System.Text.Json NuGet-Paket. Das Paket unterstützt:

  • .NET Standard 2.0 und neuere Versionen
  • .NET Framework 4.6.1 und neuere Versionen
  • .NET Core 2.0, 2.1 und 2.2
Travis
quelle
0

Sie können das [NonSerialized]Attribut auch verwenden

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

Aus den MS-Dokumenten :

Gibt an, dass ein Feld einer serialisierbaren Klasse nicht serialisiert werden soll. Diese Klasse kann nicht vererbt werden.


Wenn Sie beispielsweise Unity verwenden ( dies gilt nicht nur für Unity ), funktioniert dies mitUnityEngine.JsonUtility

using UnityEngine;

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