Update: this is intended behavior of System.Text.Json
:
In comments Noah Stahl links to this issue
System.Text.Json.JsonSerializer.Serialize ignores JsonPropertyName on abstract properties #3979
This is known/by design. Properties cannot inherit System.Text.Json attributes. The attributes need to be placed on each (de)serializable override.
As a workaround, you could make make SortValue
be a public, non-virtual surrogate that calls some protected abstract property like so:
public abstract class Base
{
protected abstract IComparable ProtectedSortValue { get; }
[JsonIgnore]
public IComparable SortValue => ProtectedSortValue;
}
public class Derived : Base
{
public int VoteCount { get; set; }
protected override IComparable ProtectedSortValue => VoteCount;
}
With this change, SortValue
will not be serialized in derived classes while ProtectedSortValue
will not be serialized at all, since only public properties are serialized. Demo fiddle #3 here.
(Adding [JsonIgnore]
to the overridden property also prevents its serialization, however it would be necessary to do this in every derived class, which it appears you do not want to do.)
Original answer: This may be a limitation of System.Text.Json
. I was able to reproduce your problem using the following code:
var derived = new Derived { VoteCount = 101 };
var json1 = JsonSerializer.Serialize(derived, typeof(Derived));
Console.WriteLine(json1); // {"VoteCount":101,"SortValue":{}}
var json2 = JsonSerializer.Serialize(derived, typeof(Base));
Console.WriteLine(json2); //{}
When an instance of Derived
is serialized as type Derived
, the SortValue
property is included; but when serialized as type Base
it is not. Demo fiddle #1 here.
But is this behavior intended? Neither the overview docs nor the JsonIgnoreAttribute
docs discuss whether [JsonIgnore]
is inherited, however the .Net 3.1 source code for JsonIgnoreAttribute
as well as the current source show [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class JsonIgnoreAttribute : JsonAttribute
{
/// <summary>
/// Initializes a new instance of <see cref="JsonIgnoreAttribute"/>.
/// </summary>
public JsonIgnoreAttribute() { }
}
Notice that AttributeUsageAttribute.Inherited
is not set. Since the default value for Inherited
is documented as follows:
true
if the attribute can be inherited by derived classes and overriding members; otherwise, false
. The default is true
.
It seems that [JsonIgnore]
should have been inherited by the overridden property. It is certainly inconsistent with both Json.NET and DataContractJsonSerializer
, which respectively honor inheritance for Newtonsoft.Json.JsonIgnoreAttribute
and IgnoreDataMemberAttribute
as shown in demo fiddle #2 here. You might want to open an issue about this; at the minimum the documentation should be clarified.