Como ignorar uma propriedade na classe se nula, usando json.net

529

Estou usando o Json.NET para serializar uma classe para JSON.

Eu tenho a classe assim:

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

Eu quero adicionar um JsonIgnore()atributo à Test2Listpropriedade somente quando Test2Listestiver null. Se não for nulo, quero incluí-lo no meu json.

Amit
fonte

Respostas:

685

De acordo com James Newton King: Se você mesmo criar o serializador, em vez de usar JavaScriptConvert, haverá uma NullValueHandlingpropriedade que poderá ser configurada para ignorar.

Aqui está uma amostra:

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

Como alternativa, conforme sugerido por @amit

JsonConvert.SerializeObject(myObject, 
                            Newtonsoft.Json.Formatting.None, 
                            new JsonSerializerSettings { 
                                NullValueHandling = NullValueHandling.Ignore
                            });
Mrchief
fonte
159
Isso funciona: JsonConvert.SerializeObject (myObject, Newtonsoft.Json.Formatting.None, novo JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
Amit
ele trabalhou para mim, mas eu tinha que usar JsonSerializerSettingsnão JsonSerializercomo ele mostrou um erro para o último
Yazan
1
uma coisa importante - funciona apenas com as classes concretas (Pessoa, Conta, etc.). quando eu tentei isso com dicionário, não funcionou
chester89
1
Eu tenho o mesmo problema que @ chester89. Com um ExpandoObject, os valores nulos não são ignorados. Isso parece ser um bug (usando json.net 9.0.1)
kwrl
2
Quando a resposta foi escrita, o JSON.Net nem suportava objetos dinâmicos. :) No momento, você pode usar um conversor personalizado para fazer seus lances.
Mrchief
923

Uma solução alternativa usando o JsonPropertyatributo:

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

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

Como visto neste documento online .

sirthomas
fonte
19
A resposta aceita é melhor porque não polui suas classes com atributos Json.net.
Sergey
117
@ Emery depende do seu caso de uso. Se você deseja tê-lo apenas para propriedades específicas (conforme mencionado na pergunta), esta é a resposta correta. Se você deseja uma resposta global, defina a propriedade no JsonSerializer.
Sibbl
Concordo - isso é simples e elegante. Vale a pena votar. Funciona muito bem - basta definir uma propriedade no objeto que você deseja serializar como Nothing no VB e ele não faz mais parte do JSON. Isso só funcionará com Strings. As propriedades que são enumerações ou números inteiros sempre serão exibidas - a configuração como Nothing resulta no valor padrão de "0", independentemente.
Destek
3
@Destek, você precisa tornar os campos do tipo referências nulos, para que não sejam serializados usando atributo ou configuração.
Tony
1
Para evitar 'poluir' suas classes com muitos atributos, você também pode atribuir a regra de manipulação [JsonObject], mas observe que o nome do atributo é diferente. [resposta editada]
Simon_Weaver
60

Semelhante à resposta de @ sirthomas, o JSON.NET também respeita a EmitDefaultValuepropriedade em DataMemberAttribute:

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

Isso pode ser desejável se você já estiver usando [DataContract]e [DataMember]no seu tipo de modelo e não quiser adicionar atributos específicos ao JSON.NET.

Tobias J
fonte
1
Isso é tão útil! Eu estava projetando uma classe Exception personalizada e não queria adicionar coisas do Json.net lá. Obrigado!
Jspgrassi # 10/15
2
Isso não estava funcionando no .Net Core. Resposta de Recomend @sirthomas: use [JsonProperty (NullValueHandling = NullValueHandling.Ignore)]
Derrick
1
Funciona bem para mim no .Net Core com o Newtonsoft.Json 10.0.2.
Karl-Johan Sjögren
33

Você pode escrever: [JsonProperty("property_name",DefaultValueHandling = DefaultValueHandling.Ignore)]

Ele também cuida de não serializar propriedades com valores padrão (não apenas nulos). Pode ser útil para enumerações, por exemplo.

Vatsal Patel
fonte
3
É exatamente o mesmo que a resposta de sirthomas, por que você a adicionou?
OMGtechy 23/10/19
4
Para sua informação espécie, não há diferença entre DefaultValueHandling e NullValueHandling ...
Vatsal Patel
4
Você poderia explicar isso na sua resposta então? À primeira vista, parece o mesmo, e agora você mencionou isso, não indica como isso é diferente da outra resposta / como a complementa.
OMGtechy 25/10
1
Embora a resposta aceita possa ser útil em algumas circunstâncias, nem sempre é possível usá-la. Isto é exatamente o que o médico pediu.
Melbourne Developer
1
Eu acho que é isso que eu queria. Manuseio específico em determinadas propriedades, não em todas.
Frostymarvelous
23

Você pode fazer isso para ignorar todos os nulos em um objeto que você está serializando, e quaisquer propriedades nulas não aparecerão no JSON

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

Como pode ser visto neste link em seu site (http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx) I suporte usando [Padrão ()] para especificar valores padrão

Retirado do link

   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
fonte
3

No .Net Core, isso é muito mais fácil agora. No seu startup.cs, adicione as opções json e você poderá definir as configurações lá.


public void ConfigureServices(IServiceCollection services)

....

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

Com o 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 });

O resultado será:

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

Com System.Text.Jsone .NET Core 3.0, isso funcionou para mim:

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

Para explicar um pouco a resposta muito útil da GlennG (traduzir a sintaxe de C # para VB.Net nem sempre é "óbvia"), você também pode decorar propriedades de classes individuais para gerenciar como os valores nulos são tratados. Se você fizer isso, não use o JsonSerializerSettings global da sugestão da GlennG; caso contrário, ele substituirá as decorações individuais. Isso é útil se você deseja que um item nulo apareça no JSON, para que o consumidor não precise fazer nenhum tratamento especial. Se, por exemplo, o consumidor precisar saber que uma matriz de itens opcionais está normalmente disponível, mas está vazia no momento ... A decoração na declaração de propriedade é semelhante a esta:

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

Para aquelas propriedades que você não deseja que apareçam na alteração JSON : = NullValueHandling.Include a : = NullValueHandling.Ignore . A propósito - eu descobri que você pode decorar uma propriedade para serialização XML e JSON muito bem (apenas coloque-as uma ao lado da outra). Isso me dá a opção de chamar o serializador XML no dotnet ou o NewtonSoft à vontade - ambos trabalham lado a lado e meus clientes têm a opção de trabalhar com XML ou JSON. Isso é liso como ranho em uma maçaneta, pois tenho clientes que exigem os dois!

Destek
fonte
0

Aqui está uma opção semelhante, mas oferece outra opção:

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

Então, eu uso assim:

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

A diferença aqui é que:

  • Reduz o código repetido, instanciando e configurando JsonSerializerSettingscada local que é usado.
  • Economiza tempo na configuração de todas as propriedades de cada objeto a ser serializado.
  • Ainda oferece aos outros desenvolvedores flexibilidade nas opções de serialização, em vez de ter a propriedade especificada explicitamente em um objeto reutilizável.
  • Meu caso de uso é que o código é uma biblioteca de terceiros e não quero forçar opções de serialização em desenvolvedores que desejam reutilizar minhas classes.
  • As desvantagens potenciais são que esse é outro objeto que outros desenvolvedores precisariam conhecer ou se seu aplicativo é pequeno e essa abordagem não importaria para uma única serialização.
Joe Mayo
fonte
-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
fonte
settings.NullValueHandling = NullValueHandling.Ignore é sugerido em outras respostas. Não está claro, o que é novo em sua resposta
Michael Freidgeim