Comment exclure une propriété de la sérialisation Json

235

J'ai une classe DTO que je sérialise

Json.Serialize(MyClass)

Comment puis-je en exclure une propriété publique ?

(Il doit être public, car je l'utilise dans mon code ailleurs)

Elad Benda
la source
4
Quel cadre de sérialisation utilisez-vous?
Pavel Gatilov
37
IgnoreDataMember ScriptIgnore JsonIgnoreselon le sérialiseur que vous utilisez
LB
3
il convient également de noter l'attribut [NonSerialized], qui n'est applicable qu'aux champs (et non aux propriétés), mais a par ailleurs le même effet que JsonIgnore.
Triynko
Le commentaire de Trynko est très utile .... si vous utilisez IgnoreDataMember sur un champ il n'y aura pas d'erreur, mais il ne sera pas appliqué.
Tillito

Réponses:

147

Si vous utilisez System.Web.Script.Serializationdans le framework .NET, vous pouvez mettre un ScriptIgnoreattribut sur les membres qui ne doivent pas être sérialisés. Voir l'exemple tiré d' ici :

Considérons le cas (simplifié) suivant:

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

Dans ce cas, seules les propriétés Id et Name seront sérialisées, ainsi l'objet JSON résultant ressemblerait à ceci:

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

PS. N'oubliez pas d'ajouter une référence à " System.Web.Extensions" pour que cela fonctionne

Pavel Krymets
la source
10
J'ai trouvé ScriptIgnoredans l' System.Web.Script.Serializationespace de noms.
Sorangwala Abbasali
355

Si vous utilisez l' attribut Json.Net, vous ignorerez[JsonIgnore] simplement le champ / la propriété lors de la sérialisation ou de la désérialisation.

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

Ou vous pouvez utiliser l'attribut DataContract et DataMember pour sérialiser / désérialiser sélectivement les propriétés / champs.

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

Reportez-vous http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size pour plus de détails

JC Raja
la source
37
Si j'étais l'OP, je préférerais cette réponse à la solution [ScriptIgnore] choisie. Principalement en raison de la congruence d'une solution Json donc d'un problème Json. Pourquoi impliquer System.Web.Extensions lorsque la bibliothèque que vous utilisez fournit une solution? Le meilleur IMHO absolu est l'attribut [IgnoreDataMember], car System.Runtime.Serialization devrait être compatible avec tous les sérialiseurs si vous souhaitez échanger Json.
Steve H.
IgnoreDataMemberne fonctionne pas avec le JsonResultsérialiseur par défaut .
hendryanw
1
NewtonSoft vient de m'aider pleinement. Cela a rendu mon json propre sans aucune propriété désordonnée incluse dans mes modèles qui sont juste pour le backend.
Sorangwala Abbasali
1
@JC Raja Comment puis-je ignorer une propriété pendant le dessalement uniquement lorsque cette propriété est nulle
user123456
1
[NewtonSoft.Json] Je souhaite ignorer la sérialisation uniquement. Alors une solution pour ça?
Trương Quốc Khánh
31

Vous pouvez utiliser [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); }
    }
}

Référence ici

Dans ce cas, l'ID puis le nom ne seront sérialisés

Arion
la source
1
L'URL de votre réponse est cassée. [ScriptIgnore]Qu'est - ce qui devrait être utilisé sur la propriété si votre contrôleur utilise le contrôleur MVC de base return Json(...?
Don Cheadle
2
Je sais que c'est un vieux commentaire, mais oui, utilisez-le [ScriptIgnore]dans MVC Controller. Soyez averti cependant, si vous utilisez SignalR , vous devez [JsonIgnore]également l' utiliser .
Sam
22

Désolé, j'ai décidé d'écrire une autre réponse car aucune des autres réponses n'est suffisamment copiable.

Si vous ne voulez pas décorer les propriétés avec certains attributs, ou si vous n'avez pas accès à la classe, ou si vous voulez décider quoi sérialiser pendant l'exécution, etc. etc. voici comment vous le faites dans 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;
    }
}

Usage

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

J'ai publié le code ici au cas où quelqu'un voudrait ajouter quelque chose

https://github.com/jitbit/JsonIgnoreProps

MISE À JOUR IMPORTANTE: assurez-vous de mettre en cache l' ContractResolverobjet si vous décidez d'utiliser cette réponse, sinon les performances pourraient en souffrir.

Alex
la source
15

Si vous ne souhaitez pas décorer le code avec des attributs comme je le suis, surtout lorsque vous ne pouvez pas dire au moment de la compilation ce qui se passera ici est ma solution.

Utilisation du sérialiseur Javascript

    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
la source
1
Un changement mineur dans la logique et le PropertyExclusionConverterpeut être transformé en a PropertyInclusionConverter.
Zarepheth
c'est tout simplement génial
SaiKiran Mandhala
Un problème potentiel avec cela est qu'il doit effectuer le travail de correspondance et d'exclusion à chaque fois qu'un objet est sérialisé. Cependant, une fois compilées, les propriétés d'un type ne changeront pas - vous devez pré-calculer, par type, les noms à inclure et réutiliser simplement la liste sur chaque ligne. Pour une tâche de sérialisation JSON très massive, la mise en cache peut faire une différence notable dans les performances.
ErikE
9

Si vous utilisez, System.Text.Jsonvous pouvez utiliser [JsonIgnore].
FQ:System.Text.Json.Serialization.JsonIgnoreAttribute

Documents officiels de Microsoft: JsonIgnoreAttribute

Comme indiqué ici :

La bibliothèque est intégrée dans le cadre du framework partagé .NET Core 3.0.
Pour les autres frameworks cibles, installez le package System.Text.Json NuGet. Le package prend en charge:

  • .NET Standard 2.0 et versions ultérieures
  • .NET Framework 4.6.1 et versions ultérieures
  • .NET Core 2.0, 2.1 et 2.2
Travis
la source
0

Vous pouvez également utiliser l' [NonSerialized]attribut

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

Depuis les documents MS :

Indique qu'un champ d'une classe sérialisable ne doit pas être sérialisé. Cette classe ne peut pas être héritée.


Si vous utilisez Unity par exemple ( ce n'est pas seulement pour Unity ), cela fonctionne avecUnityEngine.JsonUtility

using UnityEngine;

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