Comment ignorer une propriété de la classe si null, en utilisant json.net

529

J'utilise Json.NET pour sérialiser une classe en JSON.

J'ai la classe comme ça:

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

Je veux ajouter un JsonIgnore()attribut à la Test2Listpropriété uniquement lorsque l' Test2Listest null. S'il n'est pas nul, je veux l'inclure dans mon json.

Amit
la source

Réponses:

685

Selon James Newton King: si vous créez le sérialiseur vous-même plutôt que d'utiliser JavaScriptConvert, il existe une NullValueHandlingpropriété que vous pouvez définir pour ignorer.

Voici un exemple:

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

Alternativement, comme suggéré par @amit

JsonConvert.SerializeObject(myObject, 
                            Newtonsoft.Json.Formatting.None, 
                            new JsonSerializerSettings { 
                                NullValueHandling = NullValueHandling.Ignore
                            });
Mrchief
la source
159
Cela fonctionne: JsonConvert.SerializeObject (myObject, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
Amit
cela a fonctionné pour moi, mais je n'ai JsonSerializerSettingspas dû utiliser JsonSerializercar cela a montré une erreur pour le dernier
Yazan
1
une chose importante - cela ne fonctionne qu'avec les classes concrètes (Personne, Compte, etc.). quand j'ai essayé avec Dictionary, cela n'a pas fonctionné
chester89
1
J'ai le même problème que @ chester89. Avec un ExpandoObject, les valeurs nulles ne sont pas ignorées. Cela semble être un bug (en utilisant json.net 9.0.1)
kwrl
2
Lorsque la réponse a été écrite, JSON.Net ne supportait même pas les objets dynamiques. :) Pour le moment, vous pouvez utiliser un convertisseur personnalisé pour faire vos enchères.
Mrchief
923

Une solution alternative utilisant l' JsonPropertyattribut:

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

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

Comme vu dans ce document en ligne .

sirthomas
la source
19
La réponse acceptée est meilleure car elle ne pollue pas vos classes avec des attributs Json.net.
Sergey
117
@Sergey cela dépend de votre cas d'utilisation. Si vous ne voulez l'avoir que pour des propriétés spécifiques (comme mentionné dans la question), alors c'est la bonne réponse. Si vous souhaitez une réponse globale, vous devez définir la propriété dans JsonSerializer.
sibbl
D'accord - c'est simple et élégant. Vaut le vote. Fonctionne très bien - définissez simplement une propriété dans l'objet que vous souhaitez sérialiser sur Nothing dans VB et il ne fait plus partie du JSON. Cela ne fonctionnera cependant qu'avec des chaînes. Les propriétés qui sont des énumérations ou des nombres entiers s'afficheront toujours - la définition de Nothing entraîne la valeur par défaut de "0".
Destek
3
@Destek vous devez rendre les champs de type références nullables, puis ils ne seront pas sérialisés en utilisant un attribut ou un paramètre.
Tony
1
Pour éviter de «polluer» vos classes avec de nombreux attributs, vous pouvez également affecter la règle de gestion [JsonObject], mais notez que le nom de l'attribut est différent. [réponse modifiée]
Simon_Weaver
60

Semblable à la réponse de @ sirthomas, JSON.NET respecte également la EmitDefaultValuepropriété sur DataMemberAttribute:

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

Cela peut être souhaitable si vous utilisez déjà [DataContract]et [DataMember]dans votre type de modèle et que vous ne souhaitez pas ajouter d'attributs spécifiques à JSON.NET.

Tobias J
la source
1
C'est tellement utile! Je concevais une classe d'exception personnalisée et je ne voulais pas y ajouter de contenu Json.net. Merci!
jpgrassi
2
Cela ne fonctionnait pas dans .Net Core. Recommandez la réponse @sirthomas: utilisez [JsonProperty (NullValueHandling = NullValueHandling.Ignore)]
Derrick
1
Cela fonctionne bien pour moi dans .Net Core avec Newtonsoft.Json 10.0.2.
Karl-Johan Sjögren
33

Tu peux écrire: [JsonProperty("property_name",DefaultValueHandling = DefaultValueHandling.Ignore)]

Il prend également soin de ne pas sérialiser les propriétés avec des valeurs par défaut (pas seulement null). Cela peut être utile pour les énumérations par exemple.

Vatsal Patel
la source
3
C'est exactement la même chose que la réponse de sirthomas, pourquoi l'avez-vous ajoutée?
OMGtechy
4
Pour votre information, il y a une différence entre DefaultValueHandling et NullValueHandling ...
Vatsal Patel
4
Pourriez-vous l'expliquer dans votre réponse alors? À première vue, cela a la même apparence, et maintenant vous l'avez mentionné, cela n'indique pas en quoi cela est différent de l'autre réponse / comment il le complète.
OMGtechy
1
Bien que la réponse acceptée puisse être utile dans certaines circonstances, il n'est pas toujours possible de l'utiliser. C'est exactement ce que le médecin a ordonné.
Melbourne Developer
1
Je pense que c'est ce que je voulais. Manipulation spécifique sur certaines propriétés, pas toutes.
frostymarvelous
23

Vous pouvez le faire pour ignorer toutes les valeurs nulles dans un objet que vous sérialisez, et aucune propriété nulle n'apparaîtra alors dans le JSON

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

Comme on peut le voir sur ce lien sur leur site (http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx) I prise en charge en utilisant [Default ()] pour spécifier les valeurs par défaut

Tiré du lien

   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
la source
3

Dans .Net Core, c'est beaucoup plus facile maintenant. Dans votre startup.cs, ajoutez simplement les options json et vous pouvez y configurer les paramètres.


public void ConfigureServices(IServiceCollection services)

....

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

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

Le résultat sera:

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

Avec System.Text.Jsonet .NET Core 3.0, cela a fonctionné pour moi:

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

Pour exposer légèrement la réponse très utile de GlennG (la traduction de la syntaxe de C # en VB.Net n'est pas toujours "évidente"), vous pouvez également décorer des propriétés de classe individuelles pour gérer la façon dont les valeurs nulles sont gérées. Si vous faites cela, n'utilisez pas le JsonSerializerSettings global de la suggestion de GlennG, sinon il remplacera les décorations individuelles. Cela est pratique si vous voulez qu'un élément nul apparaisse dans le JSON afin que le consommateur n'ait pas à faire de manipulation spéciale. Si, par exemple, le consommateur a besoin de savoir qu'un tableau d'éléments facultatifs est normalement disponible, mais est actuellement vide ... La décoration de la déclaration de propriété ressemble à ceci:

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

Pour les propriétés que vous ne souhaitez pas voir apparaître du tout dans la modification JSON : = NullValueHandling.Include to : = NullValueHandling.Ignore . Soit dit en passant - j'ai trouvé que vous pouvez très bien décorer une propriété pour la sérialisation XML et JSON (mettez-les juste à côté les unes des autres). Cela me donne la possibilité d'appeler le sérialiseur XML dans dotnet ou le sérialiseur NewtonSoft à volonté - les deux travaillent côte à côte et mes clients ont la possibilité de travailler avec XML ou JSON. C'est lisse comme morve sur une poignée de porte car j'ai des clients qui ont besoin des deux!

Destek
la source
0

Voici une option similaire, mais offrant un autre choix:

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

Ensuite, je l'utilise comme ceci:

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

La différence ici est que:

  • Réduit le code répété en instanciant et en configurant JsonSerializerSettings chaque emplacement utilisé.
  • Gagne du temps dans la configuration de chaque propriété de chaque objet à sérialiser.
  • Donne toujours aux autres développeurs une flexibilité dans les options de sérialisation, plutôt que d'avoir la propriété explicitement spécifiée sur un objet réutilisable.
  • Mon cas d'utilisation est que le code est une bibliothèque tierce et je ne veux pas forcer les options de sérialisation sur les développeurs qui voudraient réutiliser mes classes.
  • Les inconvénients potentiels sont qu'il s'agit d'un autre objet que les autres développeurs devraient connaître, ou si votre application est petite et que cette approche n'aurait pas d'importance pour une seule sérialisation.
Joe Mayo
la source
-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
la source
settings.NullValueHandling = NullValueHandling.Ignore est suggéré dans d'autres réponses. Pas clair, ce qui est nouveau dans votre réponse
Michael Freidgeim