Flogex
Flogex

Reputation: 664

How to ignore null values in a JSON dictionary with JSON.NET

When serializing a dictionary with JSON.NET, it seems like the NullValueHandling setting is ignored.

var dict = new Dictionary<string, string>
{
    ["A"] = "Some text",
    ["B"] = null
};

var json = JsonConvert.SerializeObject(dict, Formatting.Indented,
    new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore
    });

Console.WriteLine(json);

Output:

{
  "A": "Some text",
  "B": null
}

I expected that only the key-value pair with key "A" is present in the JSON output and the pair for "B" is omitted.

How can I tell JSON.NET to only serialize the entries that do not contain null values?

Upvotes: 7

Views: 6050

Answers (3)

RoadRunner
RoadRunner

Reputation: 26315

I would just filter out the null values from the original dictionary with LINQ and serialize the filtered dictionary:

using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;

namespace JsonSerialize {
    public static class Program {
        private static Dictionary<string, string> dict = new Dictionary<string, string> {
            ["A"] = "Some text",
            ["B"] = null
        };

        public static void Main(string[] args) {
            var filtered = dict
                .Where(p => p.Value != null)
                .ToDictionary(p => p.Key, p => p.Value);

            var json = JsonConvert.SerializeObject(filtered, Formatting.Indented);

            Console.WriteLine (json);
        }
    }
}

Which gives:

{
  "A": "Some text"
}

Upvotes: 4

Justin Soderstrom
Justin Soderstrom

Reputation: 71

The NullValueHandling setting is only applicable to class properties and not dictionaries. There doesn't appear to be a built-in way in JSON.NET to ignore null values in a dictionary.

If you want JSON.NET to handle this case for you, then you can create a custom JSON converter and override the WriteJson method to handle the null values.

public class CustomJsonConverter : JsonConverter
{
    public override bool CanRead => false;

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Dictionary<string, string>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var dictionary = (Dictionary<string, string>)value;

        writer.WriteStartObject();

        foreach (var pair in dictionary)
        {
            if (pair.Value != null)
            {
                writer.WritePropertyName(pair.Key);

                serializer.Serialize(writer, pair.Value);
            }
        }

        writer.WriteEndObject();
    }
}

Which then you can use like this:

var json = JsonConvert.SerializeObject(dict, Formatting.Indented, new CustomJsonConverter());

Upvotes: 4

Yola
Yola

Reputation: 19033

The main idea of serialization is that after deserialization you should have the same object back. Most likely that is illogical to leave out keys with null values from a dictionary because keys per se represent some data. But that is ok to not save null fields because after deserialization you would still have the same object because these fields would be initialized to null by default.

And, this would work fine for class fields if they are nulls. Look at this example:

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"
// }

In your case values for certain keys are nulls, but that's not the same as in the documentation provided.

This might help you, but you should be aware of how ToDictionary affects performance:

var json = JsonConvert.SerializeObject(dict.Where(p => p.Value != null)
    .ToDictionary(p => p.Key, p => p.Value), Formatting.Indented);

Upvotes: 2

Related Questions