As noted in Issue #38878: System.Text.Json option to ignore default values in serialization & deserialization, as of .Net Core 3 there is no equivalent to the DefaultValueHandling functionality in System.Text.Json.
.NET 5 and later introduce JsonIgnoreAttribute.Condition, which has the following values:
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.
/// This is applied to both reference and value-type properties and fields.
WhenWritingDefault = 2,
/// If the value is <see langword="null"/>, the property is ignored during serialization.
/// This is applied only to reference-type properties and fields.
WhenWritingNull = 3,
}
While JsonIgnoreCondition superficially resembles DefaultValueHandling, System.Text.Json ignores custom default values applied via DefaultValueAttribute. Instead the default value used is always default(T). E.g. the following combination of attributes:
[DefaultValue(true)]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
[JsonPropertyName("send_service_notification")]
public bool SendServiceNotification { get; set; }
Will result in SendServiceNotification being skipped when false not true. In addition, System.Text.Json will not automatically populate the default value onto your model if not present in the JSON.
That being said, you are using DefaultValueHandling.Populate:
Members with a default value but no JSON will be set to their default value when deserializing.
If your properties are mutable, this can be achieved by setting the default value in the constructor or property initializer:
//[DefaultValue(true)] not needed by System.Text.Json
[System.Text.Json.Serialization.JsonPropertyName("send_service_notification")]
public bool SendServiceNotification { get; set; } = true;
Demo fiddle here.
If you are using immutable properties that are set only via a parameterized constructor, in .NET 6 (and possibly .NET 5, I haven't checked) you can specify a default value in the constructor argument list and it will be honored by System.Text.Json when not present in the JSON. E.g. if you have a record:
public record SendServiceRecord (bool SendServiceNotification = true);
And you deserialize the JSON {}, then SendServiceNotification will be true after deserialization.
See demo fiddles here and here.
In fact the documentation for DefaultValueAttribute recommends code initialization of default values:
A DefaultValueAttribute will not cause a member to be automatically initialized with the attribute's value. You must set the initial value in your code.