Cómo ignorar una propiedad en clase si es nula, usando json.net

529

Estoy usando Json.NET para serializar una clase a JSON.

Tengo la clase como esta:

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

Quiero agregar un JsonIgnore()atributo a la Test2Listpropiedad solo cuando Test2Listsea null. Si no es nulo, entonces quiero incluirlo en mi json.

Amit
fuente

Respuestas:

685

Según James Newton King: si crea el serializador usted mismo en lugar de usar JavaScriptConvert, hay una NullValueHandlingpropiedad que puede configurar para ignorar.

Aquí hay una muestra:

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

Alternativamente, como lo sugiere @amit

JsonConvert.SerializeObject(myObject, 
                            Newtonsoft.Json.Formatting.None, 
                            new JsonSerializerSettings { 
                                NullValueHandling = NullValueHandling.Ignore
                            });
Mrchief
fuente
159
Esto funciona: JsonConvert.SerializeObject (myObject, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
Amit
Se trabajó para mí, pero tuve que usar JsonSerializerSettingsno JsonSerializer, ya que mostró un error para el último
Yazan
1
Una cosa importante: funciona solo con las clases concretas (Persona, Cuenta, etc.). cuando probé esto con Dictionary, no funcionó
chester89
1
Tengo el mismo problema que @ chester89. Con un ExpandoObject, los valores nulos no se ignoran. Eso parece ser un error (usando json.net 9.0.1)
kwrl
2
Cuando se escribió la respuesta, JSON.Net ni siquiera admitía objetos dinámicos. :) Por el momento, puede utilizar un convertidor personalizado para hacer su oferta.
Mrchief
923

Una solución alternativa que utiliza el JsonPropertyatributo:

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

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

Como se ve en este documento en línea .

sirthomas
fuente
19
La respuesta aceptada es mejor porque no contamina sus clases con los atributos de Json.net.
Sergey
117
@Sergey depende de su caso de uso. Si solo desea tenerlo para propiedades específicas (como se menciona en la pregunta), entonces esta es la respuesta correcta. Si desea una respuesta global, debe establecer la propiedad en JsonSerializer.
sibbl
De acuerdo: esto es simple y elegante. Vale la pena votar. Funciona muy bien: solo establezca una propiedad en el objeto que desea serializar en Nothing en VB y ya no forma parte de JSON. Sin embargo, esto solo funcionará con Strings. Las propiedades que son enumeraciones o números enteros siempre se mostrarán; si se establece en Nothing, independientemente del valor predeterminado será "0".
Destek
3
@Destek necesita hacer que los campos de tipo de referencias sean anulables, luego no se serializarán utilizando el atributo o la configuración.
Tony
1
Para evitar 'contaminar' sus clases con muchos atributos, también puede asignar la regla de manejo [JsonObject], pero tenga en cuenta que el nombre del atributo es diferente. [respuesta editada]
Simon_Weaver
60

Similar a la respuesta de @ sirthomas, JSON.NET también respeta la EmitDefaultValuepropiedad en DataMemberAttribute:

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

Esto puede ser deseable si ya está utilizando [DataContract]y [DataMember]en su tipo de modelo y no desea agregar atributos específicos de JSON.NET.

Tobias J
fuente
1
¡Esto es muy útil! Estaba diseñando una clase de excepción personalizada y no quería agregar cosas de Json.net allí. ¡Gracias!
jpgrassi
2
Esto no funcionaba en .Net Core. Recomiendo la respuesta de @sirthomas: use [JsonProperty (NullValueHandling = NullValueHandling.Ignore)]
Derrick
1
Me funciona bien en .Net Core con Newtonsoft.Json 10.0.2.
Karl-Johan Sjögren
33

Puedes escribir: [JsonProperty("property_name",DefaultValueHandling = DefaultValueHandling.Ignore)]

También se ocupa de no serializar propiedades con valores predeterminados (no solo nulos). Puede ser útil para enumeraciones, por ejemplo.

Vatsal Patel
fuente
3
Esto es exactamente lo mismo que la respuesta de sirthomas, ¿por qué lo agregaste?
OMGtechy
44
Para su amable información, hay una diferencia entre DefaultValueHandling y NullValueHandling ...
Vatsal Patel
44
¿Podrías explicarlo en tu respuesta entonces? A primera vista, se ve igual, y ahora que ha mencionado eso, no indica cómo esto es diferente de la otra respuesta / cómo lo complementa.
OMGtechy
1
Si bien la respuesta aceptada puede ser útil en algunas circunstancias, no siempre es posible usarla. Esto es justo lo que recetó el médico.
Melbourne Developer
1
Creo que esto es lo que quería. Manejo específico de ciertas propiedades, no todas.
frostymarvelous
23

Puede hacer esto para ignorar todos los valores nulos en un objeto que está serializando, y las propiedades nulas no aparecerán en el JSON

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

Como se puede ver en este enlace en su sitio (http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx) I admite el uso de [Predeterminado ()] para especificar valores predeterminados

Tomado del enlace

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

En .Net Core esto es mucho más fácil ahora. En su startup.cs simplemente agregue las opciones de json y puede configurar las configuraciones allí.


public void ConfigureServices(IServiceCollection services)

....

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

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

El resultado será:

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

Con System.Text.Jsony .NET Core 3.0 esto funcionó para mí:

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

Para exponer un poco la respuesta muy útil de GlennG (traducir la sintaxis de C # a VB.Net no siempre es "obvio") también puede decorar propiedades de clase individuales para administrar cómo se manejan los valores nulos. Si hace esto, no use el JsonSerializerSettings global de la sugerencia de GlennG, de lo contrario, anulará las decoraciones individuales. Esto es útil si desea que aparezca un elemento nulo en el JSON para que el consumidor no tenga que hacer ningún manejo especial. Si, por ejemplo, el consumidor necesita saber que una variedad de artículos opcionales está normalmente disponible, pero actualmente está vacía ... La decoración en la declaración de propiedad se ve así:

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

Para aquellas propiedades que no desea que aparezcan en absoluto en el cambio JSON : = NullValueHandling.Incluye en : = NullValueHandling.Ignore . Por cierto, descubrí que puedes decorar una propiedad para la serialización XML y JSON muy bien (solo ponlas una al lado de la otra). Esto me da la opción de llamar al serializador XML en dotnet o al serializador NewtonSoft a voluntad, ambos trabajan lado a lado y mis clientes tienen la opción de trabajar con XML o JSON. ¡Esto es resbaladizo como un moco en un picaporte porque tengo clientes que requieren ambos!

Destek
fuente
0

Aquí hay una opción que es similar, pero ofrece otra opción:

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

Entonces, lo uso así:

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

La diferencia aquí es que:

  • Reduce el código repetido creando instancias y configurando JsonSerializerSettingscada lugar donde se usa.
  • Ahorra tiempo en la configuración de cada propiedad de cada objeto a serializar.
  • Todavía ofrece a otros desarrolladores flexibilidad en las opciones de serialización, en lugar de tener la propiedad especificada explícitamente en un objeto reutilizable.
  • Mi caso de uso es que el código es una biblioteca de terceros y no quiero forzar las opciones de serialización en los desarrolladores que deseen reutilizar mis clases.
  • Los inconvenientes potenciales son que es otro objeto que otros desarrolladores necesitarían saber, o si su aplicación es pequeña y este enfoque no importaría para una sola serialización.
Joe Mayo
fuente
-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
fuente
settings.NullValueHandling = NullValueHandling.Ignore se sugiere en otras respuestas. No está claro, qué hay de nuevo en su respuesta
Michael Freidgeim