You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WPF自定义JSON转换器:对象数组转数组数组适配Python服务端

C# WPF向Python服务端发送JSON格式适配问题

我有一个C# WPF应用程序,需要向独立运行的Python服务端发送JSON请求。目前已经通过ListBox、ObservableCollection和JsonSerializer实现了部分成功通信,代码如下:

try
{
    // PeekSignalsList 是 ObservableCollection
    StringContent? jsonString = new StringContent(
        JsonConvert.SerializeObject(PeekSignalsList, Formatting.Indented), 
        Encoding.UTF8, 
        new MediaTypeHeaderValue("application/json"));

    if (jsonString is not null)
    {
        Client.DefaultRequestHeaders.Clear();
        Client.DefaultRequestHeaders.Add("host", $"{ServerAddress}");
        Client.DefaultRequestHeaders.Add("user-agent", "python-requests/2.31.0");
        Client.DefaultRequestHeaders.Add("accept-encoding", "gzip, deflate");
        Client.DefaultRequestHeaders.Add("accept", "*/*");
        Client.DefaultRequestHeaders.Add("connection", "keep-alive");
        Client.DefaultRequestHeaders.TryAddWithoutValidation("content-type", "application/json");

        // 这段代码可以正常工作
        var request = new System.Net.Http.HttpRequestMessage
        {
            Method = System.Net.Http.HttpMethod.Get,
            RequestUri = new Uri($"http://{ServerAddress}/peek_data"),
            Content = jsonString,
        };

        var response = await Client.SendAsync(request).ConfigureAwait(false);
        response.EnsureSuccessStatusCode();

        var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    }
    else
    {
        PeekLog += $"ECI-PeekOneShot:	Json serialization returned null{Environment.NewLine}";
    }
}    

格式不匹配导致请求被拒

我还有一个ListView控件,其两个字段绑定到另一个PokeSignal类型的ObservableCollection。使用上述相同方法发送请求时,Wireshark捕获到的JSON格式与Python测试脚本发送的格式存在差异,导致服务端拒绝请求。

Python测试脚本发送的JSON格式(Wireshark捕获)

JSON raw form:
    [
        [
            "counter",
            11
        ]
    ]

对应的结构解析:

Array
Array
[Path with value: /[]/[]:counter]
[Member with value: []:counter]
String value: counter
[Path with value: /[]/[]:11]
[Member with value: []:11]
Number value: 11

C#程序发送的JSON格式(Wireshark捕获)

JSON raw form:
    [
        {
            "SignalName": "counter",
            "SignalValue": 0
        }
    ]

对应的结构解析:

Array
Object
Member: SignalName
[Path with value: /[]/SignalName:counter]
[Member with value: SignalName:counter]
String value: counter
Key: SignalName
[Path: /[]/SignalName]
Member: SignalValue
[Path with value: /[]/SignalValue:0]
[Member with value: SignalValue:0]
Number value: 0
Key: SignalValue
[Path: /[]/SignalValue]

自定义序列化转换器的尝试及错误

我知道需要自定义JSON序列化器来生成数组的数组格式,但尝试后遇到问题。

PokeSignal类代码

namespace EngineeringLabUi.Models
{
    [JsonConverter(typeof(PokeSignalJsonConverter))]
    public class PokeSignal
    {
        public PokeSignal(string? signalName, int? signalValue)
        {
            SignalName = signalName;
            SignalValue = signalValue;
        }

        public PokeSignal()
        {
            SignalName = string.Empty;
            SignalValue = 0;
        }

        // 不确定这里该怎么实现
        public override string ToString() => $"{SignalName}:{SignalValue}";

        public static PokeSignal Parse(string input)
        {
            // 不确定这里该怎么实现
            int value = int.Parse(input.Substring(0, input.Length - 1));
            string name = input;

            return new PokeSignal(name, value);
        }

        public string? SignalName { get; set; }
        public int? SignalValue { get; set; }

    }
}

自定义转换器代码

namespace EngineeringLabUi.Converters
{
    public class PokeSignalJsonConverter : JsonConverter<PokeSignal>
    {
        public override PokeSignal? ReadJson(JsonReader reader,
                                             Type objectType,
                                             PokeSignal? existingValue,
                                             bool hasExistingValue,
                                             Newtonsoft.Json.JsonSerializer serializer)
        {
            return PokeSignal.Parse(reader.ToString()!);
        }

        public override void WriteJson(JsonWriter writer,
                                       PokeSignal? value,
                                       Newtonsoft.Json.JsonSerializer serializer)
        {
            writer.WriteRaw(value?.ToString());
        }
    }
}

使用转换器时的错误

尝试使用转换器时出现编译错误:

try
{
    var serializeOptions = new JsonSerializerOptions
    {
        WriteIndented = true,
        Converters =
        {
            /* 错误: 无法将类型 'EngineeringLabUi.Converters.PokeSignalJsonConverter' 转换为
             *  'System.Text.Json.Serialization.JsonConverter'
             *
             * 错误: 集合初始化器的最佳重载 Add 方法 'ICollection<JsonConverter>.Add(JsonConverter)'
             * 具有一些无效参数    
             */
            new PokeSignalJsonConverter()
        }
    };
    StringContent? jsonString = new StringContent(
        JsonConvert.SerializeObject(PokeSignalsList, Formatting.Indented),
        Encoding.UTF8,
        new MediaTypeHeaderValue("application/json"));

    if (jsonString is not null)
    {
        Client.DefaultRequestHeaders.Clear();
        Client.DefaultRequestHeaders.Add("host", $"{ServerAddress}");
        Client.DefaultRequestHeaders.Add("user-agent", "python-requests/2.31.0");
        Client.DefaultRequestHeaders.Add("accept-encoding", "gzip, deflate");
        Client.DefaultRequestHeaders.Add("accept", "*/*");
        Client.DefaultRequestHeaders.Add("connection", "keep-alive");
        Client.DefaultRequestHeaders.TryAddWithoutValidation("content-type", "application/json");

        var request = new System.Net.Http.HttpRequestMessage
        {
            Method = System.Net.Http.HttpMethod.Get,
            RequestUri = new Uri($"http://{ServerAddress}/poke_data"),
            Content = jsonString,
        };

        var response = await Client.SendAsync(request).ConfigureAwait(false);
        response.EnsureSuccessStatusCode();
    }
    else
    {
        PokeLog += $"ECI-PokeOneShot:	Json serialization returned null{Environment.NewLine}";
    }
}

最终解决方案

核心问题在于混淆了不同JSON序列化包(Newtonsoft.Json和System.Text.Json)的转换器,以及对序列化逻辑的误解。更新后的PokeSignal代码如下:

[Newtonsoft.Json.JsonConverter(typeof(ObjectToArrayConverter<PokeSignal>))]
[DataContract]
public class PokeSignal(string? signalName, int? signalValue)
{
    public PokeSignal() : this(string.Empty, 0)
    {
    }

    [JsonProperty(Order = 1)]
    public string? SignalName { get; set; } = signalName;

    [JsonProperty(Order = 12)]
    public int? SignalValue { get; set; } = signalValue;
}

学习要点

  • 明确目标JSON格式的结构要求
  • 区分使用的JSON序列化包(Newtonsoft.Json vs System.Text.Json),两者的转换器不兼容
  • 自定义转换器需正确重写读写方法,对应目标格式的解析与生成逻辑
  • 通过特性标记指定要使用的转换器,确保序列化时正确调用
  • 调用序列化方法时需匹配对应的包(如使用JsonConvert.SerializeObject对应Newtonsoft.Json)

内容的提问来源于stack exchange,提问作者Michael Riley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:07:26