Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Text.Json option to ignore default values during serialization #779

Closed
karthickthangasamy opened this issue Jun 25, 2019 · 13 comments · Fixed by #36322
Closed

System.Text.Json option to ignore default values during serialization #779

karthickthangasamy opened this issue Jun 25, 2019 · 13 comments · Fixed by #36322
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-System.Text.Json
Milestone

Comments

@karthickthangasamy
Copy link

karthickthangasamy commented Jun 25, 2019

Updated by @layomia. I'm pasting the API approved in #35649, along with API review notes. An option to ignore defaults on deserialization was not added, as we couldn't identify a reasonable scenario that requires this. This proposal does not include a way to specify a custom default. This is discussed in #36236.

Video

  • Looks great. Only suggestion is to change WhenWritingDefaultValues to WhenWritingDefault.
  • JsonSerializerOptions.DefaultIgnoreCondition should throw ArgumentException rather than InvalidOperationException
namespace System.Text.Json.Serialization
{
    public enum JsonIgnoreCondition
    {
        Never = 0,
        Always = 1,
        WhenWritingDefault = 2
    }    
}

namespace System.Text.Json
{
    public partial class JsonSerializerOptions
    {
        public JsonIgnoreCondition DefaultIgnoreCondition { get; set; } = JsonIgnoreCondition.Never;
    }
}
Original proposal (click to view)

There is no option to ignore the DefaultValues for the properties in System.Text.Json.

The JSON.NET contains this options to ignore default values.

https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_DefaultValueHandling.htm

Usecase scenario:

For updating the Blazor component model, need to send the values which has only changes to component and refresh the UI, even for initial rendering of component itself, we will the default values.

return JsonSerializer.ToString(this, this.GetType(), new JsonSerializerOptions
{
     IgnoreNullValues = true,
     WriteIndented = true                
});
@judeleander
Copy link

judeleander commented Nov 1, 2019

Currently there is no support for Ignoring Default Values while Serialization in System.Text.Json, which is required for ignoring default value for value types (Data type), as mentioned earlier by @karthickthangasamy the same support is available in Json.NET, this can be achieved by adding an API IgnoreDefaultValues to the Json Serializer Options and then validating a condition to check if the IgnoreDefaultValues API is set true and the value is default value before serializing only for the value types since it cannot be provided for reference types.

Proposed API

IgnoreDefaultValues API is proposed similar to existing API IgnoreNullValues

/// <summary>
/// Determines whether default values are ignored during serialization and deserialization.
/// The default value is false.
/// </summary>
/// <exception cref="InvalidOperationException">
/// Thrown if this property is set after serialization or deserialization has occurred.
/// </exception>
public bool IgnoreDefaultValues
{
     get
     {
          return _ignoreDefaultValues;
     }
     set
     {
          VerifyMutable();
          _ignoreDefaultValues = value;
     }
}
bool includeProperty = true;

// Check default value property.
if (options.IgnoreDefaultValues)
{
    DefaultValueAttribute defaultValueAttribute = JsonPropertyInfo.GetAttribute<DefaultValueAttribute>(jsonPropertyInfo.PropertyInfo);
    currentValue = jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue);
    includeProperty = (defaultValueAttribute != null && object.Equals(currentValue, defaultValueAttribute.Value)) == false;
}

if (includeProperty)
{
    jsonPropertyInfo.Write(ref state, writer);
}

Details

  • Added API IgnoreDefaultValues for getting input from user if default values are to be ignored while JSON serialization using JsonSerializerOptions in System.Text.Json.
  • Implemented the same by validating if IgnoreDefaultValues API is set to true by user and the value to be serialized is a default value and if so the same is ignored and move to next property while serialization.

Pull Request

A PR with the proposed changes is available: #42288

@nickevansuk
Copy link

@layomia following on from https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/api-review-process.md, who is the owner of this suggestion? Is there anything we can we do to help move this through discussion?

@layomia
Copy link
Contributor

layomia commented Dec 11, 2019

From @SanderSade in #681:

JSON.NET has DefaultValueHandling enumeration, which allows users to determine how the default values are handled during de/serialization.

Similar functionality would be very useful in System.Text.Json, as DefaultValueHandling.Ignore/IgnoreAndPopulate would allow considerable reduction of JSON size in many cases.

@layomia layomia transferred this issue from dotnet/corefx Dec 11, 2019
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Text.Json untriaged New issue has not been triaged by the area owner labels Dec 11, 2019
@layomia
Copy link
Contributor

layomia commented Dec 12, 2019

@nickevansuk we are planning for 5.0 and this issue is being discussed. The next step is to create a formal API proposal. The proposal should include API modifications, rationale, usage scenarios and code examples, and raise any open questions. This would be a good way to help move this along. Here is an example of a good one: https://github.com/dotnet/corefx/issues/4547#issue-117426449.

This proposal should be added to this thread, and we'll merge it into the description of this issue for greater visibility. I'll own the feature and drive it through framework core API review.

Some things to consider for this issue:

  • granularity: should the option be global (on JsonSerializerOptions), per-property (probably leveraging the JsonIgnoreCondition enum being proposed in https://github.com/dotnet/corefx/issues/40600), or both?
  • scope: should the option be applied to serialization, deserialization, or both?
  • how to indicate the default value
    • this could be with an attribute: Should the DefaultValueAttribute in System.ComponentModel be used, or should System.Text.Json implement a new one. Plays into the larger question of whether S.T.Json should use [external attributes](https://github.com/dotnet/corefx/issues/38758, https://github.com/dotnet/corefx/issues/41578).
    • there could be a new "catch all" attribute like Newtonsoft's JsonPropertyAttribute which could contain properties like DefaultValue, IgnoreCondition, and prevent numerous attributes being added to satisfy other features (e.g. something like JsonIncludeAttribute to support properties with non-public setter/getters - https://github.com/dotnet/corefx/issues/38163).
    • presumably, the default value would fallback to default(typeof(PropertyInQuestion)) if none is provided.

@bjornen77
Copy link
Contributor

Regarding:
"granularity: should the option be global (on JsonSerializerOptions), per-property (probably leveraging the JsonIgnoreCondition enum being proposed in dotnet/corefx#40600), or both?"

If the granularity is per-property, this could probably be used to solve:
#512

@danenglish2
Copy link

danenglish2 commented Dec 22, 2019

Is there an ETA for this feature in an upcoming release? My JSON class has many bools and it would be nice to default them all to false which would greatly reduce the serialized size.

@michalhosala
Copy link

Don't want to point out obvious but for the time being one can make value type fields nullable and use IgnoreNullValues = true to get around this limitation.

@danenglish2
Copy link

Don't want to point out obvious but for the time being one can make value type fields nullable and use IgnoreNullValues = true to get around this limitation.

Yes I did consider this. My models are used with a Razor engine application and bool? will not bind to checkboxes unfortunately.

@layomia layomia removed the untriaged New issue has not been triaged by the area owner label Feb 20, 2020
@layomia layomia added this to the 5.0 milestone Feb 20, 2020
@layomia layomia added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Feb 20, 2020
@aktxyz
Copy link

aktxyz commented Apr 26, 2020

in progress ... woot !

@layomia
Copy link
Contributor

layomia commented May 11, 2020

I updated the issue description with API approved in #35649. Specifying a custom default is discussed in #36236.

@layomia layomia added api-approved API was approved in API review, it can be implemented and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation labels May 11, 2020
@layomia layomia changed the title System.Text.Json option to ignore default values in serialization & deserialization System.Text.Json option to ignore default values during serialization May 11, 2020
@layomia layomia self-assigned this May 11, 2020
@rubo
Copy link

rubo commented Jun 27, 2020

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.

@loic-sharma
Copy link
Contributor

loic-sharma commented Jul 13, 2020

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.

@layomia
Copy link
Contributor

layomia commented Jul 14, 2020

@rubo, @loic-sharma this will be addressed with #39152.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Text.Json
Projects
None yet
Development

Successfully merging a pull request may close this issue.