Runtime: System.Text.Json: Ignore null values while serializing

Created on 12 Jul 2020  路  4Comments  路  Source: dotnet/runtime

Background and Motivation

Recently JsonIgnoreCondition have been changed to have WhenWritingDefault rather than WhenNull.
See:
image

When serving JSON for frontends, then default values of value types are extremely important. It's not like null.
You could argue that undefined and null have "similar" semantic in Javascript, so not having the null field serialized makes sense. It will be undefined, and checks you would do against null such as if (!value) will match the undefined behavior too.
While for value types you don't expect that it can become undefined, so you'll end up with subtle bugs after deserialization.

That's why I believe that WhenWritingNull makes a lot of sense.
JSON.NET has a similar feature, see: https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_NullValueHandling.htm

Remarks:

  • I cannot think of deserialization usages that make sense, that's why I proposed WhenWritingNull.
  • Options.IgnoreNullValues is not a solution, since it recently became obsolete.

Proposed API

WhenWritingNull is the new enum entry.

```c#
public enum JsonIgnoreCondition
{
///


/// Property is never ignored during serialization or deserialization.
///

Never = 0,
///
/// Property is always ignored during serialization and deserialization.
///

Always = 1,
///
/// If the value is the default, the property is ignored during serialization.
///

WhenWritingDefault = 2,
///
/// If the value is null, the property is ignored during serialization.
///

WhenWritingNull = 3,
}

While working on a regression for https://github.com/dotnet/runtime/issues/38800 I wrote a PR that fixed both the regression and proposed the change, see here: https://github.com/dotnet/runtime/pull/38811.
That should have been separate PRs, so the PR got rejected, but you can see a baseline there.

## Usage Examples

In global options:

```c#
public class MyClass
{
    public int[] ReferenceType { get; set; }

    public int ValueType { get; set; }
}

[Fact]
public static void Serialize_value_type_but_not_reference_type()
{
    var options = new JsonSerializerOptions
    {
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenNull
    };

    string json = @"{""ReferenceType"":null, ""ValueType"":18}";

    var obj = JsonSerializer.Deserialize<MyClass>(json, options);

    // Deserialize
    Assert.Null(obj.ReferenceType);
    Assert.Equal(18, obj.ValueType);

    // Deserialize
    obj = new MyClass();
    json = JsonSerializer.Serialize(obj, options);
    Assert.Equal(@"{""ValueType"":0}", json);
}

On top of properties:

```c#
public class MyClass
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int[] ReferenceType { get; set; }

public int ValueType { get; set; }

}

[Fact]
public static void Serialize_value_type_but_not_reference_type()
{
string json = @"{""ReferenceType"":null, ""ValueType"":18}";

var obj = JsonSerializer.Deserialize<MyClass>(json);

// Deserialize
Assert.Null(obj.ReferenceType);
Assert.Equal(18, obj.ValueType);

// Deserialize
obj = new MyClass();
json = JsonSerializer.Serialize(obj);
Assert.Equal(@"{""ValueType"":0}", json);

}
```

api-approved area-System.Text.Json

Most helpful comment

Video

  • Makes perfect sense.

C# public enum JsonIgnoreCondition { // Never = 0, // Always = 1, // WhenWritingDefault = 2, WhenWritingNull = 3 }

All 4 comments

From @rubo in https://github.com/dotnet/runtime/issues/779:

Currently, with WhenWritingDefault, it doesn't serialize, for instance, int type with the default value. There's should be an option to skip nullable types but still serialize non-nullable types. I don't need to receive anything in JSON that is null but I do want to receive fields with values of 0. In JavaScript apps, having something undefined or 0 makes a big difference. In a nutshell, WhenWritingDefault makes int fields of 0 to become undefined in JavaScript client. For now, I use int? instead of int as a workaround which is not a good solution.

From @loic-sharma in https://github.com/dotnet/runtime/issues/779:

I ran into the same issue as @rubo when updating my app to .NET 5. The current JsonIgnoreCondition.WhenWritingDefault is a breaking change that feels a little too strong. Would it be possible to add a JsonIgnoreCondition.WhenNull that skips null values but writes defaults like 0 and false? This comment indicates that JsonIgnoreCondition.WhenNull was removed - why is that?

For context, my app implements the NuGet protocol. This protocol requires some integer and boolean properties even if they have default values (for example, the search API must return a downloads value even if a package has 0 downloads). However, this protocol also has optional properties that should be omitted if they have a value of null (for example, the package metadata API should omit the deprecation property if a package is not deprecated). Adding JsonIgnoreAttributes everywhere as needed is rather inconvenient.

Video

  • Makes perfect sense.

C# public enum JsonIgnoreCondition { // Never = 0, // Always = 1, // WhenWritingDefault = 2, WhenWritingNull = 3 }

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jamesqo picture jamesqo  路  3Comments

GitAntoinee picture GitAntoinee  路  3Comments

bencz picture bencz  路  3Comments

chunseoklee picture chunseoklee  路  3Comments

iCodeWebApps picture iCodeWebApps  路  3Comments