使用 System.Text.Json 的自定义类型继承 Dictionary 的序列化不会序列化其他属性

Serialisation of custom type inheriting Dictionary using System.Text.Json does not serialise other properties

我有以下类型:

public class Product : Dictionary<string, object>
{
    [JsonInclude]
    public string ProductId { get; set; }

    public Product(string productId) : base()
    {
        ProductId = productId;
    }
}

当使用 System.Text.Json 进行序列化时,它不包括属性(即 ProductId)。 添加或删除 [JsonInclude] 似乎没有任何效果。

测试用例:

[Fact]
public void SimpleTest()
{
    var p = new Product("ABC123");
    p["foo"] = "bar";
    var json = JsonSerializer.Serialize(p);
    Assert.Contains("productId", json, StringComparison.OrdinalIgnoreCase);
}

并收到输出:

{"foo":"bar"}

如何让它在序列化期间将我的自定义属性包含在我的类型中? (注意:不要关心反序列化)。

System.Text.Json 不序列化字典属性。 我在 MSFT 文档的任何地方都找不到说明这一点的地方,但 System.Text.Json 仅序列化字典键和值。这可以从 DictionaryOfTKeyTValueConverter<TCollection, TKey, TValue> 的参考来源得到确认,这是用于您的类型的转换器。

这可能是因为:

  1. 可能存在与 属性.
  2. 同名的密钥
  3. 应用程序开发人员几乎肯定不希望序列化 CountIsReadOnly 等“标准”字典属性。
  4. 早期的序列化程序以相同的方式运行,System.Text.Json 遵循先例。 Newtonsoft 是 documented to only serialize dictionary keys and values. DataContractJsonSerializer (with ),JavaScriptSerializer 也是。

作为替代方案,您可以考虑使用不同的数据模型,其中 Product 不继承自 Dictionary,而是具有 [JsonExtensionData] public Dictionary<string, object> Properties { get; set; } 属性:

public class Product 
{
    public string ProductId { get; set; }

    [System.Text.Json.Serialization.JsonExtensionData]
    public Dictionary<string, object> Properties { get; set; } = new ();

    public Product(string productId) : base()
    {
        ProductId = productId;
    }
}

[JsonExtensionData] 属性导致字典属性在序列化和反序列化时作为父对象的一部分包含在内。

备注:

  • 如果建议的替代方案不可接受,您将需要编写自定义 JsonConverter 来手动序列化 Product 字典的 .NET 属性和键值。

  • [JsonInclude]添加到ProductId不会强制其序列化。根据docs for JsonInclude当应用于属性时,[它]表示非public的getter和setter可以用于序列化和反序列化。 所以这里不相关,因为 ProductId 已经有 public getter 和 setter。

  • Newtonsoft 也有一个 JsonExtensionData 属性(做同样的事情)。如果您同时使用这两种序列化程序,请小心使用正确的属性。

  • 在你的问题中,你说 不关心反序列化 但反序列化确实可以与 JsonExtensionData 一起正常工作。

演示 fiddle here.