702

I am using Json.NET to serialize a class to JSON.

I have the class like this:

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

I want to add a JsonIgnore() attribute to Test2List property only when Test2List is null. If it is not null then I want to include it in my json.

Vito Gentile
  • 13,336
  • 9
  • 61
  • 96
Amit
  • 25,106
  • 25
  • 75
  • 116

17 Answers17

1225

An alternate solution using the JsonProperty attribute:

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

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

As seen in this online doc.

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
sirthomas
  • 12,576
  • 1
  • 13
  • 15
  • 27
    The accepted answer is better because it doesn't pollute your classes with Json.net attributes. – Sergey Aug 14 '15 at 03:27
  • 190
    @Sergey it depends on your use case. If you only want to have it for specific properties (as mentioned in the question), then this is the correct answer. If you want a global answer, you should set the property in the JsonSerializer. – sibbl Jan 14 '16 at 10:05
  • 1
    Agreed - this is simple and elegant. Worth upvoting. Works great - just set a property in the object you want to serialize to Nothing in VB and it is no longer part of the JSON. This will only work with Strings though. Properties that are enums or integers will always show up - setting to Nothing results in the default value of "0" regardless. – Destek Apr 10 '17 at 15:50
  • 5
    @Destek you need to make references type fields nullable, then they won't be serialized using attribute or setting. – Tony Jan 17 '18 at 19:53
  • 4
    To avoid 'polluting' your classes with many attributes you can also assign the handling rule on `[JsonObject]`, but note that the attribute name is different. [edited answer] – Simon_Weaver Dec 29 '18 at 01:25
  • @sibbl if you want to differently serialize different properties, than serialization is not problem you should solve, but inconsistency in your code. – 100r Jan 15 '19 at 11:45
  • 2
    Hmm, can't get [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] to work: The type or namespace name 'ItemNullValueHandling' could not be found. I did add using Newtonsoft.Json.Serialization; ... – Jimmy Jan 09 '20 at 16:07
  • This is the best answer when you have special case for some attributes. This doesn't pollut it makes it better in some cases. – Marcus Lagerstedt Mar 05 '20 at 08:36
  • is this answer valid for NET 2.0 standard? – thanili May 18 '23 at 00:10
854

As per James Newton King: If you create the serializer yourself rather than using JavaScriptConvert there is a NullValueHandling property which you can set to ignore.

Here's a sample:

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

Alternatively, as suggested by @amit

JsonConvert.SerializeObject(myObject, 
                            Newtonsoft.Json.Formatting.None, 
                            new JsonSerializerSettings { 
                                NullValueHandling = NullValueHandling.Ignore
                            });
Mrchief
  • 75,126
  • 20
  • 142
  • 189
  • 173
    This works :JsonConvert.SerializeObject(myObject, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore}); – Amit Jun 28 '11 at 14:34
  • it worked for me but i had to use `JsonSerializerSettings` not `JsonSerializer` as it showed an error for the last one – Yazan Feb 24 '16 at 08:08
  • @Yazan it shouldn't. They are practically the same thing. It could be something else messing up. – Mrchief Feb 24 '16 at 16:41
  • 2
    one important thing - it works only with the concrete classes (Person, Account, etc.). when I tried this with Dictionary, it didn't work – chester89 Apr 15 '16 at 10:31
  • 1
    I've the same problem as @chester89. With an ExpandoObject null values are not ignored. That seems to be a bug (using json.net 9.0.1) – kwrl Jul 05 '16 at 09:05
  • 2
    When the answer was written, JSON.Net didn't even support dynamic objects. :) At the moment, you can use a custom converter to do your bidding. – Mrchief Jul 05 '16 at 15:27
  • JSON.NET considered zero as null and ignores the zero values. How can we resolve this.? – Karthick Jun 25 '19 at 10:20
  • 1
    Cannot get it to work... I get empty parenthesis {"propName":{}} – singhswat Aug 02 '21 at 23:21
76

JSON.NET also respects the EmitDefaultValue property on DataMemberAttribute, in case you don't want to add Newtonsoft-specific attributes to your model:

[DataMember(Name="property_name", EmitDefaultValue=false)]
Tobias J
  • 19,813
  • 8
  • 81
  • 66
44

You can write: [JsonProperty("property_name",DefaultValueHandling = DefaultValueHandling.Ignore)]

It also takes care of not serializing properties with default values (not only null). It can be useful for enums for example.

Vatsal Patel
  • 571
  • 5
  • 11
  • 4
    This is exactly the same as sirthomas's answer, why did you add it? – OMGtechy Oct 23 '17 at 16:34
  • 5
    For your kind information, there is difference between DefaultValueHandling and NullValueHandling... – Vatsal Patel Oct 25 '17 at 09:35
  • 7
    Could you explain it in your answer then? At first glance, it looks the same, and now you've mentioned that, it doesn't state how this is different from the other answer / how it compliments it. – OMGtechy Oct 25 '17 at 10:06
  • 1
    While the accepted answer may be useful in some circumstances, it's not always possible to use it. This is just what the doctor ordered. – Christian Findlay Jun 20 '18 at 10:05
  • 2
    I think this is what I wanted. Specific handling on certain properties, not all. – frostymarvelous Aug 23 '18 at 18:35
  • 1
    If at first glance it looks the same, then sometimes you need to glance again :-) – Simon_Weaver Dec 29 '18 at 01:21
  • 1
    Upvoted because I can also set this in `JsonSerializerSettings` whilst calling `JsonConvert.SerializeObject`. Thanks! – Adam Cox Mar 20 '19 at 01:59
  • this is useful for things like ignoring enum when you use `[JsonConverter(typeof(StringEnumConverter))]` to map strings to enum values, when the string is null it will be mapped to default enum value which you can ignore with defaultValueHandling. – KingKongCoder Sep 05 '19 at 17:29
29

You can do this to ignore all nulls in an object you're serializing, and any null properties won't then appear in the JSON

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
var myJson = JsonConvert.SerializeObject(myObject, settings);
CMedina
  • 4,034
  • 3
  • 24
  • 39
Chris Halcrow
  • 28,994
  • 18
  • 176
  • 206
24

In my case, using .NET 6 this was the solution:

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

More info here.

Brugner
  • 527
  • 8
  • 16
  • 2
    Thanks for this - many of the other answers are assuming the use of JSON.net which isn't really necessary anymore. – mdryden Nov 21 '22 at 20:00
12

As can be seen in this link on their site (http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx) I support using [Default()] to specify default values

Taken from the 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
  • 2,508
  • 2
  • 30
  • 37
11

In .Net Core this is much easier now. In your startup.cs just add json options and you can configure the settings there.


public void ConfigureServices(IServiceCollection services)

....

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

Draken
  • 3,134
  • 13
  • 34
  • 54
Hizzy
  • 741
  • 7
  • 27
10

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

The result will be:

{
   "Name": "Bad Boys III",
   "Description": "It's no Bad Boys"
 }
Rafy
  • 817
  • 1
  • 7
  • 9
10

With System.Text.Json and .NET Core 3.0 this worked for me:

var jsonSerializerOptions = new JsonSerializerOptions()
{
    IgnoreNullValues = true
};
var myJson = JsonSerializer.Serialize(myObject, jsonSerializerOptions );
Pascal R.
  • 2,024
  • 1
  • 21
  • 35
  • 3
    IgnoreNullValues is deprecated apparently, you can now use: `DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull` – Christiaan Aug 25 '22 at 14:26
4

An adaption to @Mrchief's / @amit's answer, but for people using VB

 Dim JSONOut As String = JsonConvert.SerializeObject(
           myContainerObject, 
           New JsonSerializerSettings With {
                 .NullValueHandling = NullValueHandling.Ignore
               }
  )

See: "Object Initializers: Named and Anonymous Types (Visual Basic)"

https://msdn.microsoft.com/en-us/library/bb385125.aspx

GlennG
  • 2,982
  • 2
  • 20
  • 25
2

Or just by setting like this.

services.AddMvc().AddJsonOptions(options =>
  options.JsonSerializerOptions.IgnoreNullValues = true;
});
Oyeme
  • 11,088
  • 4
  • 42
  • 65
  • 1
    this is the correct setting for the default behauviour, but `IgnoreNullValues` has been deprecated, so instead use: `options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;` – Raul Jan 06 '23 at 11:56
1

.Net 6 - Add the code in Program.cs. This will ignore the class or record property if it is null.

using System.Text.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers()
.AddJsonOptions(opts =>
{
    var enumConverter = new JsonStringEnumConverter();
    opts.JsonSerializerOptions.Converters.Add(enumConverter);
    opts.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault | JsonIgnoreCondition.WhenWritingNull;
});
Tirtha
  • 89
  • 9
0

To expound slightly on GlennG's very helpful answer (translating the syntax from C# to VB.Net is not always "obvious") you can also decorate individual class properties to manage how null values are handled. If you do this don't use the global JsonSerializerSettings from GlennG's suggestion, otherwise it will override the individual decorations. This comes in handy if you want a null item to appear in the JSON so the consumer doesn't have to do any special handling. If, for example, the consumer needs to know an array of optional items is normally available, but is currently empty... The decoration in the property declaration looks like this:

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

For those properties you don't want to have appear at all in the JSON change :=NullValueHandling.Include to :=NullValueHandling.Ignore. By the way - I've found that you can decorate a property for both XML and JSON serialization just fine (just put them right next to each other). This gives me the option to call the XML serializer in dotnet or the NewtonSoft serializer at will - both work side-by-side and my customers have the option to work with XML or JSON. This is slick as snot on a doorknob since I have customers that require both!

Destek
  • 154
  • 1
  • 10
0

Here's an option that's similar, but provides another choice:

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

Then, I use it like this:

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

The difference here is that:

  • Reduces repeated code by instantiating and configuring JsonSerializerSettings each place it's used.
  • Saves time in configuring every property of every object to be serialized.
  • Still gives other developers flexibility in serialization options, rather than having the property explicitly specified on a reusable object.
  • My use-case is that the code is a 3rd party library and I don't want to force serialization options on developers who would want to reuse my classes.
  • Potential drawbacks are that it's another object that other developers would need to know about, or if your application is small and this approach wouldn't matter for a single serialization.
Joe Mayo
  • 7,501
  • 7
  • 41
  • 60
0

This does not exactly answer the original question, but may prove useful depending on the use case. (And since I wound up here after my search, it may be useful for others.)

In my most recent experience, I'm working with a PATCH api. If a property is specified but with no value given (null/undefined because it's js), then the property and value are removed from the object being patched. So I was looking for a way to selectively build an object that could be serialized in such a way that this would work.

I remembered seeing the ExpandoObject, but never had a true use case for it until today. This allows you to build an object dynamically, so you won't have null properties unless you want them there.

Here is a working fiddle, with the code below.

Results:

Standard class serialization
    noName: {"Name":null,"Company":"Acme"}
    noCompany: {"Name":"Fred Foo","Company":null}
    defaultEmpty: {"Name":null,"Company":null}
ExpandoObject serialization
    noName: {"Company":"Acme"}
    noCompany: {"name":"Fred Foo"}
    defaultEmpty: {}

Code:

using Newtonsoft.Json;
using System;
using System.Dynamic;
                    
public class Program
{
    public static void Main()
    {
        SampleObject noName = new SampleObject() { Company = "Acme" };
        SampleObject noCompany = new SampleObject() { Name = "Fred Foo" };
        SampleObject defaultEmpty = new SampleObject();
        
        
        Console.WriteLine("Standard class serialization");
        Console.WriteLine($"    noName: { JsonConvert.SerializeObject(noName) }");
        Console.WriteLine($"    noCompany: { JsonConvert.SerializeObject(noCompany) }");
        Console.WriteLine($"    defaultEmpty: { JsonConvert.SerializeObject(defaultEmpty) }");
        
        
        Console.WriteLine("ExpandoObject serialization");
        Console.WriteLine($"    noName: { JsonConvert.SerializeObject(noName.CreateDynamicForPatch()) }");
        Console.WriteLine($"    noCompany: { JsonConvert.SerializeObject(noCompany.CreateDynamicForPatch()) }");
        Console.WriteLine($"    defaultEmpty: { JsonConvert.SerializeObject(defaultEmpty.CreateDynamicForPatch()) }");
    }
}

public class SampleObject {
    public string Name { get; set; }
    public string Company { get; set; }
    
    public object CreateDynamicForPatch()
    {
        dynamic x = new ExpandoObject();
        
        if (!string.IsNullOrWhiteSpace(Name))
        {
            x.name = Name;
        }
        
        if (!string.IsNullOrEmpty(Company))
        {
            x.Company = Company;
        }
        
        return x;
    }
}
ps2goat
  • 8,067
  • 1
  • 35
  • 68
-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
  • 109
  • 1
  • 3