为什么 JsonSerializerContext 为包含 [ObservableProperty] 属性的模型生成空 JSON?

问题描述 投票:0回答:1

我的模型包含通过 [ObservableProperty] 工具包

CommunityToolkit.Mvvm
 字段自动生成的 
可观察属性
,我想使用 System.Text.Json
JsonSerializerContext
序列化它们。但当我这样做时,我的所有财产都消失了。我该如何解决这个问题?

这是我的代码:

using CommunityToolkit.Mvvm.ComponentModel;
using System.IO.Ports;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;

namespace WinFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            var _result = JsonSerializer.Serialize<EmptyConnection>(new EthernetConnection() {  IP="192.168.125.201",Port=9100}, new JsonSerializerOptions()
            {
                Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All),
                TypeInfoResolver = EmptyConnectionGenerationContext.Default,
                IgnoreReadOnlyProperties = true,
            });
        }

        [JsonDerivedType(typeof(EmptyConnection), typeDiscriminator: "EmptyConnection")]
        [JsonDerivedType(typeof(SerialPortConnection), typeDiscriminator: "SerialPortConnection")]
        [JsonDerivedType(typeof(EthernetConnection), typeDiscriminator: "EthernetConnection")]
        public partial class EmptyConnection : ObservableObject
        {

        }
        public partial class SerialPortConnection : EmptyConnection
        {
            [ObservableProperty]
            string _PortName = "";

            [ObservableProperty]
            int? _BaudRate = null;

            [ObservableProperty]
            Parity? _Parity = null;

            [ObservableProperty]
            int? _DataBits = null;
            [ObservableProperty]
            StopBits? _StopBits = null;
            [ObservableProperty]
            string _PortFeature = "";
        }
        public partial class EthernetConnection : EmptyConnection
        {
            [ObservableProperty]
            string _IP = "";

            [ObservableProperty]
            int _Port = 0;

        }
        [JsonSerializable(typeof(EmptyConnection))]
        [JsonSerializable(typeof(SerialPortConnection))]
        [JsonSerializable(typeof(EthernetConnection))]
        [JsonSerializable(typeof(string))]
        [JsonSerializable(typeof(int))]
        [JsonSerializable(typeof(int?))]
        [JsonSerializable(typeof(Parity?))]
        [JsonSerializable(typeof(StopBits?))]
        public partial class EmptyConnectionGenerationContext : JsonSerializerContext
        {

        }
    }
}

程序运行后,生成一个空的Json:

{"$type":"EthernetConnection"}

如果我不使用

TypeInfoResolver
中的
JsonSerializerOptions
,它将成功生成Json,如下所示:

{"$type":"EthernetConnection","IP":"192.168.125.201","Port":9100}

我的代码有什么问题?

c# .net-core system.text.json sourcegenerators community-toolkit-mvvm
1个回答
0
投票

您遇到的是使用源生成器的两种技术之间的交互错误:

  • System.Text.Json 的
    JsonSerializerContext
    使用源生成器在编译时生成指定类型的序列化器。
  • 当应用于字段时,
    CommunityToolkit.Mvvm
    [ObservableProperty]
    使用源生成器为指定字段生成可观察的属性。

您希望这两个源生成器能够协同工作,以便

CommunityToolkit.Mvvm
生成的属性将被
JsonSerializerContext
拾取并序列化,但不幸的是,这似乎没有实现。构建单个项目时,由一次源生成器生成的代码对另一个源生成器不可见。如需确认,请参阅:

那么你有什么选择?

首先,您可以按照docs中显示的模式手动实现可观察属性,删除

[ObservableProperty]
并添加字段所需的属性。例如

[ObservableProperty]
string _IP = "";

会成为

string _IP = "";
public string IP
{
    get => _IP;
    set => SetProperty(ref _IP, value);
}

其次,正如您已经注意到的,您可以使用基于反射的序列化而不是基于源生成的序列化:

var options = new JsonSerializerOptions()
{
    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All),
    //TypeInfoResolver = EmptyConnectionGenerationContext.Default, // REMOVE THIS
    IgnoreReadOnlyProperties = true,
};
var _result = JsonSerializer.Serialize<EmptyConnection>(new EthernetConnection() {  IP="192.168.125.201", Port=9100 }, options);
Console.WriteLine(_result); // {"$type":"EthernetConnection","IP":"192.168.125.201","Port":9100}

最后,按照Steven Blom这个答案的建议,您可以将数据模型和

JsonSerializerContext
提取到单独的项目中,使序列化上下文项目依赖于数据模型项目。如果这样做,您可以保证 System.Text.Json 的源生成器将看到您的数据模型的可观察属性,因为包含您的数据模型的项目已经构建。然后,您的
WinFormsApp1
代码需要引用这两个项目,以便使用
JsonSerializerContext
序列化您的数据模型。

© www.soinside.com 2019 - 2024. All rights reserved.