Jak zignorować właściwość w klasie, jeśli jest pusta, używając json.net

529

ja używam Json.NET do serializacji klasy do JSON.

Mam taką klasę:

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

Chcę dodać JsonIgnore()atrybut do Test2Listwłaściwości tylko wtedy, gdy Test2Listjest null. Jeśli nie jest zerowy, to chcę dołączyć to do mojego JSona.

Amit
źródło

Odpowiedzi:

685

Jak w przypadku Jamesa Newtona Kinga: jeśli tworzysz serializator samodzielnie, a nie JavaScriptConvert, istnieje NullValueHandlingwłaściwość którą możesz zignorować.

Oto próbka:

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

Alternatywnie, jak sugeruje @amit

JsonConvert.SerializeObject(myObject, 
                            Newtonsoft.Json.Formatting.None, 
                            new JsonSerializerSettings { 
                                NullValueHandling = NullValueHandling.Ignore
                            });
Mrchief
źródło
159
Działa to: JsonConvert.SerializeObject (myObject, Newtonsoft.Json.Formatting.None, nowy JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
Amit
zadziałało dla mnie, ale musiałem go JsonSerializerSettingsnie używać, JsonSerializerponieważ pokazywał błąd w ostatnim
Yazan
1
jedna ważna rzecz - działa tylko z konkretnymi klasami (osoba, konto itp.). kiedy próbowałem tego ze słownikiem, to nie działało
chester89 15.04.16
1
Mam ten sam problem co @ chester89. W przypadku ExpandoObject wartości zerowe nie są ignorowane. To wydaje się być błędem (przy użyciu json.net 9.0.1)
kwrl
2
Po napisaniu odpowiedzi JSON.Net nawet nie obsługiwał obiektów dynamicznych. :) W tej chwili możesz skorzystać z niestandardowego konwertera, aby wykonać licytację.
Mrchief
922

Alternatywne rozwiązanie wykorzystujące JsonPropertyatrybut:

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

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

Jak widać w tym dokumencie online .

sirthomas
źródło
19
Przyjmowana odpowiedź jest lepsza, ponieważ nie zanieczyszcza twoich klas atrybutami Json.net.
Siergiej
117
@Sergey zależy od przypadku użycia. Jeśli chcesz mieć go tylko dla określonych właściwości (jak wspomniano w pytaniu), to jest to poprawna odpowiedź. Jeśli chcesz uzyskać odpowiedź globalną, powinieneś ustawić właściwość w JsonSerializer.
sibbl
Uzgodnione - jest to proste i eleganckie. Warto ożywić. Działa świetnie - wystarczy ustawić właściwość w obiekcie, który chcesz serializować na Nic w VB i nie jest już częścią JSON. Działa to jednak tylko z ciągami. Zawsze wyświetlane są właściwości, które są wyliczeniami lub liczbami całkowitymi - ustawienie na Nic powoduje, że niezależnie od tego, domyślna wartość to „0”.
Destek
3
@Destek musisz ustawić pola typu odwołania na wartości zerowe, wówczas nie będą one serializowane przy użyciu atrybutu lub ustawienia.
Tony,
1
Aby uniknąć „zanieczyszczania” klas wieloma atrybutami, możesz także przypisać regułę obsługi [JsonObject], ale pamiętaj, że nazwa atrybutu jest inna. [zredagowana odpowiedź]
Simon_Weaver
60

Podobna do odpowiedzi @ sirthomas męska, JSON.NET szanuje również na EmitDefaultValuewłasność na DataMemberAttribute:

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

Może to być pożądane, jeśli już używasz [DataContract]i [DataMember]w swoim rodzaju modelu i nie chcą, aby dodać atrybuty JSON.NET specyficzne.

Tobias J
źródło
1
To jest bardzo pomocne! Tworzyłem niestandardową klasę wyjątków i nie chciałem tam dodawać elementów Json.net. Dzięki!
jpgrassi,
2
To nie działało w .Net Core. Poleć @sirthomas odpowiedź: użyj [JsonProperty (NullValueHandling = NullValueHandling.Ignore)]
Derrick
1
Działa dla mnie dobrze w .Net Core z Newtonsoft.Json 10.0.2.
Karl-Johan Sjögren,
33

Możesz pisać: [JsonProperty("property_name",DefaultValueHandling = DefaultValueHandling.Ignore)]

Dba również o nie serializowanie właściwości z wartościami domyślnymi (nie tylko zerowymi). Może być przydatny na przykład dla wyliczeń.

Vatsal Patel
źródło
3
To jest dokładnie to samo co odpowiedź Sirthoma, dlaczego to dodałeś?
OMGtechy
4
Dla twojej miłej informacji, istnieje różnica między DefaultValueHandling i NullValueHandling ...
Vatsal Patel
4
Czy mógłbyś zatem wyjaśnić to w swojej odpowiedzi? Na pierwszy rzut oka wygląda tak samo, a teraz o tym wspomniałeś, nie określa, jak różni się to od innej odpowiedzi / jak to uzupełnia.
OMGtechy,
1
Chociaż zaakceptowana odpowiedź może być przydatna w niektórych okolicznościach, nie zawsze jest możliwe jej użycie. Tak właśnie zamówił lekarz.
Melbourne Developer
1
Myślę, że tego właśnie chciałem. Specyficzna obsługa niektórych właściwości, nie wszystkich.
frostymarvelous
23

Możesz to zrobić, aby zignorować wszystkie wartości null w obiekcie, który szeregujesz, a żadne właściwości null nie pojawią się w JSON

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
var myJson = JsonConvert.SerializeObject(myObject, settings);
Chris Halcrow
źródło
12

Jak widać w tym linku na ich stronie (http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx) I obsługa za pomocą [Default ()] w celu określenia wartości domyślnych

Zaczerpnięte z linku

   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
źródło
3

W .Net Core jest to teraz znacznie łatwiejsze. W pliku startup.cs po prostu dodaj opcje json i tam możesz skonfigurować ustawienia.


public void ConfigureServices(IServiceCollection services)

....

services.AddMvc().AddJsonOptions(options =>
{
   options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;               
});
Hizzy
źródło
1

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

Wynik będzie:

{
   "Name": "Bad Boys III",
   "Description": "It's no Bad Boys"
 }
Rafy
źródło
1

Z System.Text.Jsoni .NET Core 3.0 to zadziałało dla mnie:

var jsonSerializerOptions = new JsonSerializerOptions()
{
    IgnoreNullValues = true
};
var myJson = JsonSerializer.Serialize(myObject, jsonSerializerOptions );
Pascal R.
źródło
0

Aby nieco wyjaśnić bardzo pomocną odpowiedź GlennG (tłumaczenie składni z C # na VB.Net nie zawsze jest „oczywiste”), możesz również udekorować właściwości poszczególnych klas, aby zarządzać sposobem obsługi wartości zerowych. Jeśli to zrobisz, nie używaj globalnego JsonSerializerSettings z sugestii GlennG, w przeciwnym razie zastąpi to poszczególne dekoracje. Jest to przydatne, jeśli chcesz, aby pusty element pojawiał się w JSON, aby konsument nie musiał wykonywać żadnych specjalnych czynności. Jeśli na przykład konsument musi wiedzieć, że zestaw opcjonalnych elementów jest zwykle dostępny, ale obecnie jest pusty ... Dekoracja w deklaracji właściwości wygląda następująco:

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

W przypadku właściwości, których nie chcesz, aby pojawiały się w zmianie JSON : = NullValueHandling.Include to : = NullValueHandling.Ignore . Nawiasem mówiąc - odkryłem, że możesz dobrze udekorować właściwość zarówno dla serializacji XML, jak i JSON (po prostu umieść je obok siebie). Daje mi to możliwość wywoływania serializatora XML w dotnet lub serializatora NewtonSoft do woli - zarówno praca obok siebie, jak i moi klienci mają opcję pracy z XML lub JSON. To jest gładkie jak smark na klamce, ponieważ mam klientów, którzy wymagają obu!

Destek
źródło
0

Oto podobna opcja, ale daje inny wybór:

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

Następnie używam tego w ten sposób:

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

Różnica polega na tym, że:

  • Zmniejsza powtarzający się kod, tworząc instancję i konfigurując JsonSerializerSettingskażde używane miejsce.
  • Oszczędza czas w konfiguracji każdej właściwości każdego obiektu do serializacji.
  • Nadal zapewnia innym programistom elastyczność w zakresie opcji serializacji, zamiast wyraźnego określania właściwości obiektu wielokrotnego użytku.
  • Mój przypadek użycia polega na tym, że kod jest biblioteką innej firmy i nie chcę wymuszać opcji serializacji dla programistów, którzy chcieliby ponownie wykorzystać moje klasy.
  • Potencjalne wady polegają na tym, że jest to kolejny obiekt, o którym inni programiści musieliby wiedzieć, lub jeśli twoja aplikacja jest mała i takie podejście nie miałoby znaczenia dla pojedynczej serializacji.
Joe Mayo
źródło
-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
źródło
settings.NullValueHandling = NullValueHandling.Ignore jest sugerowane w innych odpowiedziach. Nie jest jasne, co nowego w twojej odpowiedzi
Michael Freidgeim