Как игнорировать свойство в классе, если ноль, используя json.net

529

Я использую Json.NET для сериализации класса в JSON.

У меня есть такой класс:

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

Я хочу добавить JsonIgnore()атрибут к Test2Listсвойству только тогда, когда Test2Listесть null. Если это не ноль, то я хочу включить его в мой JSON.

Amit
источник

Ответы:

685

Согласно Джеймсу Ньютону Кингу: если вы создаете сериализатор самостоятельно, а не с помощью JavaScriptConvert, существует NullValueHandlingсвойство, которое вы можете установить, чтобы игнорировать.

Вот пример:

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

В качестве альтернативы, как предложено @amit

JsonConvert.SerializeObject(myObject, 
                            Newtonsoft.Json.Formatting.None, 
                            new JsonSerializerSettings { 
                                NullValueHandling = NullValueHandling.Ignore
                            });
Mrchief
источник
159
Это работает: JsonConvert.SerializeObject (myObject, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
Амит
это сработало для меня, но я должен был использовать JsonSerializerSettingsне так, JsonSerializerкак он показал ошибку для последнего
Yazan
1
Одна важная вещь - она ​​работает только с конкретными классами (Person, Account и т. д.). когда я попробовал это с помощью словаря, это не сработало
chester89
1
У меня та же проблема, что и у @ chester89. С ExpandoObject нулевые значения не игнорируются. Кажется, это ошибка (используется json.net 9.0.1)
kwrl
2
Когда был написан ответ, JSON.Net даже не поддерживал динамические объекты. :) На данный момент вы можете использовать пользовательский конвертер, чтобы делать ставки.
Mrchief
923

Альтернативное решение с использованием JsonPropertyатрибута:

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

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

Как видно из этого онлайн-документа .

sirthomas
источник
19
Принятый ответ лучше, потому что он не загрязняет ваши классы атрибутами Json.net.
Сергей
117
@ Сергей, это зависит от вашего варианта использования. Если вы хотите иметь его только для определенных свойств (как указано в вопросе), то это правильный ответ. Если вы хотите получить глобальный ответ, вы должны установить свойство в JsonSerializer.
Сиббл
Договорились - это просто и элегантно. Стоит воздержаться. Отлично работает - просто установите свойство в объекте, который вы хотите сериализовать, на Nothing в VB, и оно больше не является частью JSON. Это будет работать только со строками. Свойства, которые являются перечислениями или целыми числами, всегда будут отображаться - при значении Nothing значение по умолчанию равно «0» независимо от этого.
Destek
3
@Destek вам нужно сделать поля типа ссылок обнуляемыми, тогда они не будут сериализованы с использованием атрибута или установки.
Тони
1
Чтобы избежать «загрязнения» ваших классов многими атрибутами, вы также можете назначить правило обработки [JsonObject], но обратите внимание, что имя атрибута отличается. [отредактированный ответ]
Simon_Weaver
60

Подобный ответ @ sirthomas'S, JSON.NET также уважает в EmitDefaultValueсобственность на DataMemberAttribute:

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

Это может быть желательным , если вы уже используете [DataContract]и [DataMember]в типа модели и не хочет , чтобы добавить JSON.NET специфических атрибутов.

Тобиас Дж
источник
1
Это так полезно! Я разрабатывал собственный класс Exception и не хотел добавлять туда материал Json.net. Спасибо!
jpgrassi 10.09.15
2
Это не работает в .Net Core. Рекомендовать ответ @sirthomas: использовать [JsonProperty (NullValueHandling = NullValueHandling.Ignore)]
Derrick
1
Он прекрасно работает для меня в .Net Core с Newtonsoft.Json 10.0.2.
Карл-Йохан Шегрен
33

Ты можешь написать: [JsonProperty("property_name",DefaultValueHandling = DefaultValueHandling.Ignore)]

Это также заботится о том, чтобы не сериализовать свойства со значениями по умолчанию (не только нуль). Это может быть полезно, например, для перечислений.

Ватсал Патель
источник
3
Это точно так же, как ответ Сиртома, почему вы добавили его?
OMGtechy
4
Для вашей доброй информации, есть разница между DefaultValueHandling и NullValueHandling ...
Ватсал Патель
4
Не могли бы вы объяснить это в своем ответе тогда? На первый взгляд, это выглядит так же, и теперь вы упомянули, что не говорится, как это отличается от другого ответа / как оно дополняет его.
OMGtechy
1
Хотя принятый ответ может быть полезен в некоторых обстоятельствах, его не всегда возможно использовать. Это как раз то, что доктор прописал.
Разработчик из Мельбурна
1
Я думаю, что это то, что я хотел. Специфическая обработка определенных свойств, а не всех.
морозное
23

Вы можете сделать это, чтобы игнорировать все пустые значения в сериализуемом объекте, и любые нулевые свойства не будут отображаться в JSON

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
var myJson = JsonConvert.SerializeObject(myObject, settings);
Крис Хэлкроу
источник
12

Как видно по этой ссылке на их сайте (http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reduc-serialized-json-size.aspx) я поддержка использования [Default ()] для указания значений по умолчанию

Взято по ссылке

   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
// }
Микки Перлштейн
источник
3

В .Net Core это теперь намного проще. В вашем файле startup.cs просто добавьте параметры json, и вы сможете настроить их там.


public void ConfigureServices(IServiceCollection services)

....

services.AddMvc().AddJsonOptions(options =>
{
   options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;               
});
Hizzy
источник
1

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

Результатом будет:

{
   "Name": "Bad Boys III",
   "Description": "It's no Bad Boys"
 }
Rafy
источник
1

С System.Text.Jsonи .NET Core 3.0 это работало для меня:

var jsonSerializerOptions = new JsonSerializerOptions()
{
    IgnoreNullValues = true
};
var myJson = JsonSerializer.Serialize(myObject, jsonSerializerOptions );
Паскаль Р.
источник
0

Чтобы немного пояснить очень полезный ответ GlennG (перевод синтаксиса с C # на VB.Net не всегда «очевиден»), вы также можете декорировать свойства отдельных классов, чтобы управлять обработкой нулевых значений. Если вы сделаете это, не используйте глобальные JsonSerializerSettings из предложения GlennG, в противном случае он переопределит отдельные декорации. Это очень удобно, если вы хотите, чтобы в JSON появлялся пустой элемент, чтобы потребителю не приходилось выполнять какую-либо особую обработку. Например, если потребителю нужно знать, что массив необязательных элементов обычно доступен, но в настоящее время он пуст ... Декорация в объявлении свойства выглядит следующим образом:

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

Для этих свойств вы вообще не хотите, чтобы они отображались в JSON change : = NullValueHandling.Include to : = NullValueHandling.Ignore . Между прочим - я обнаружил, что вы можете отлично украсить свойство для сериализации XML и JSON (просто расположите их рядом друг с другом). Это дает мне возможность вызывать сериализатор XML в dotnet или сериализатор NewtonSoft по желанию - и работают бок о бок, и мои клиенты имеют возможность работать с XML или JSON. Это гладко, как сопли на дверной ручке, так как у меня есть клиенты, которым требуются оба!

Destek
источник
0

Вот вариант, который похож, но предоставляет другой выбор:

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

Затем я использую это так:

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

Разница здесь в том, что:

  • Сокращает повторяющийся код путем создания и настройки JsonSerializerSettingsкаждого места, где он используется.
  • Экономит время при настройке каждого свойства каждого объекта для сериализации.
  • Тем не менее дает другим разработчикам гибкость в параметрах сериализации, вместо того, чтобы явно указывать свойство повторно используемого объекта.
  • Мой вариант использования заключается в том, что код является сторонней библиотекой, и я не хочу навязывать опции сериализации разработчикам, которые захотят повторно использовать мои классы.
  • Потенциальные недостатки заключаются в том, что это еще один объект, о котором другие разработчики должны знать, или если ваше приложение маленькое, и этот подход не будет иметь значения для одной сериализации.
Джо Майо
источник
-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);
Суреш Бхандари
источник
settings.NullValueHandling = NullValueHandling.Ignore предлагается в других ответах. Непонятно, что нового в вашем ответе
Михаэль