Repository navigation
[API Proposal]: Add more extensive control over ignoring properties #55781
Copy link
Copy link
Closed
Labels
api-needs-workAPI needs work before it is approved, it is NOT ready for implementationAPI needs work before it is approved, it is NOT ready for implementationarea-System.Text.Json
Milestone
Description
Background and motivation
If I have this config:
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault;
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
And I return the following:
[HttpGet]
[Route("Test")]
public ActionResult Test()
{
return Ok(new
{
StringValue = "Prop",
NullString = (string)null,
DefaultNumber = 0,
EnumValue = TestEnum.Val2,
DefaultEnum = TestEnum.Val1
});
}
The result is:
{
"stringValue": "Prop",
"enumValue": "Val2"
}
This can cause confusion because the value of DefaultEnum is omitted because it's default is, but because it's converted as a string this reduces clarity.
API Proposal
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Text.Json.Serialization
{
/// <summary>
/// When specified on <see cref="JsonSerializerOptions.DefaultIgnoreCondition"/>,
/// determines when properties and fields across the type graph are ignored.
/// When specified on <see cref="JsonIgnoreAttribute.Condition"/>, controls whether
/// a property is ignored during serialization and deserialization. This option
/// overrides the setting on <see cref="JsonSerializerOptions.DefaultIgnoreCondition"/>.
/// </summary>
public enum JsonIgnoreCondition
{
/// <summary>
/// Property is never ignored during serialization or deserialization.
/// </summary>
Never = 0,
/// <summary>
/// Property is always ignored during serialization and deserialization.
/// </summary>
Always = 1,
/// <summary>
/// If the value is the default, the property is ignored during serialization.
/// This is applied to both reference and value-type properties and fields.
/// </summary>
WhenWritingDefault = 2,
/// <summary>
/// If the value is <see langword="null"/>, the property is ignored during serialization.
/// This is applied only to reference-type properties and fields.
/// </summary>
WhenWritingNull = 3,
/// <summary>
/// If the value is the default, the property is ignored during serialization.
/// This is applied to both reference and value-type properties and fields.
/// When using JsonStringEnumConverter enum properties will be included.
/// </summary>
WhenWritingDefaultExceptEnums = 4,
}
}API Usage
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefaultExceptEnums;
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});Risks
No response
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
api-needs-workAPI needs work before it is approved, it is NOT ready for implementationAPI needs work before it is approved, it is NOT ready for implementationarea-System.Text.Json
Activity
eiriktsarpalis commentedon Jul 16, 2021
Exposing a separate setting only to exempt
JsonStringEnumConverterin particular seems a bit ad-hoc to me. Perhaps one alternative might be to expose a setting that disables ignored defaults when a custom converter is being used for a type.Related to #50294. It seems clear that
WhenWritingDefaultis too much of a blunt instrument when applied at theJsonSerializerOptionslevel and too noisy when applied at the individual property level.What we could do instead is expose a mechanism for omitting properties at the converter level, for example:
and thus completely opt out JsonStringEnumConverter by default:
cc @layomia @NinoFloris
NinoFloris commentedon Jul 16, 2021
@eiriktsarpalis the proposal looks good to me, the only question to me would be whether the IgnoreProperty method is additive to or entirely overriding JsonSerializerOptions.JsonIgnoreCondition. Overriding is more powerful but I'd rather not come across too many 'constant false' converters that completely fail to respect any JsonIgnoreCondition. So it'd need some good guiding examples of how to do it right, either by looking up JsonIgnoreCondition in options or having specific converter options for it.
rogerfar commentedon Jul 16, 2021
Would it be an idea to make
DefaultIgnoreConditionnot just an enum but an options object that accept multiple conditions? It will be a breaking change but not a very difficult one to fix.[-][API Proposal]: Exempt Enums when JsonIgnoreCondition.WhenWritingDefault and JsonStringEnumConverter[/-][+][API Proposal]: Add more extensive control over ignoring properties[/+]eiriktsarpalis commentedon Oct 16, 2021
We might also want to consider #40395 for ignoring properties on the property level.
nathan-alden-sr commentedon Oct 24, 2021
I would love this capability, especially as outlined in #55781 (comment). In my case, I am trying to serialize
nullor emptyIList<T>references tonull, but I want to honor theJsonIgnoreCondition, meaning I don't want the property serialized at all if the result of my algorithm would writenull.This gets me just about all the way there, but always writes
"foos": nullregardless ofJsonIgnoreCondition.scottdorman commentedon Dec 3, 2021
I'm in need of a similar solution to what @nathan-alden-sr mentioned. As there seem to be multiple issues relating to this scenario, there is a definite need for the functionality built-in to STJ. It's not currently possible with converters (or anything else that I can find) today. I commented on a related issue #36785 (comment) that has more specifics for the scenario I'm encountering.
DavidErben commentedon Dec 10, 2021
@nathan-alden-sr I have posted a way to do this, maybe it works for you. You can check it our here:
#36785 (comment)
robertmclaws commentedon Dec 22, 2021
See my solution here: #593 (comment)
eiriktsarpalis commentedon Jan 13, 2022
I believe this could be addressed by #63686. We should make sure that this particular use case is covered and potential write a code sample demonstrating it.
Regarding converter-level predicates (#55781 (comment)), I'm increasingly of the opinion that it should be addressed on the contract model instead. Closing in favor of #63686.