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

使用System.Text.Json将NameValueCollection序列化为字典的问题

问题:System.Text.Json序列化NameValueCollection结果不符合预期

我需要实现一个转换器,用System.Text.Json处理NameValueCollection对象(已了解旧版JavaScriptSerializer的解决方案)。

执行以下代码:

NameValueCollection nvc = new NameValueCollection();
nvc.Add("foo", "bar");
nvc.Add("foo", "bar2");
nvc.Add("bar", "baz");

string json = SerializationHelper.SerializeJson(nvc, true);
Console.WriteLine(json);

得到的结果是:

[
  "foo",
  "bar"
]

这不是我想要的,期望结果是以下两种之一:
结果1(保留重复键):

{
  "foo": "bar",
  "foo": "bar2",
  "bar": "baz"
}

结果2(合并相同键值):

{
  "foo": "bar,bar2",
  "bar": "baz"
}

当前序列化方法:

public static string SerializeJson(object obj, bool pretty)
{
    if (obj == null) return null;
    string json;

    JsonSerializerOptions options = new JsonSerializerOptions();
    options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
    options.Converters.Add(new ExceptionConverter<Exception>());

    if (pretty)
    {
        options.WriteIndented = true;
        json = JsonSerializer.Serialize(obj, options);
    }
    else
    {
        options.WriteIndented = false;
        json = JsonSerializer.Serialize(obj, options);
    }

    return json;
}

请问如何实现期望的序列化行为,或是否有对应的转换器可以处理该场景?


解决方案

方案1:合并相同键的值(符合JSON规范)

实现自定义JsonConverter<NameValueCollection>,遍历集合所有键,将同一键对应的多个值用逗号拼接:

public class NameValueCollectionConverter : JsonConverter<NameValueCollection>
{
    public override NameValueCollection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 若需反序列化可自行实现,此处仅处理序列化逻辑
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, NameValueCollection value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        foreach (string key in value.AllKeys)
        {
            if (key == null) continue;
            string[] values = value.GetValues(key);
            string combinedValue = string.Join(",", values);
            writer.WriteString(key, combinedValue);
        }
        writer.WriteEndObject();
    }
}

在序列化方法中添加该转换器:

public static string SerializeJson(object obj, bool pretty)
{
    if (obj == null) return null;
    JsonSerializerOptions options = new JsonSerializerOptions();
    options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
    options.Converters.Add(new ExceptionConverter<Exception>());
    // 添加自定义NameValueCollection转换器
    options.Converters.Add(new NameValueCollectionConverter());
    
    options.WriteIndented = pretty;
    return JsonSerializer.Serialize(obj, options);
}

执行后会得到你期望的第二种结果:

{
  "foo": "bar,bar2",
  "bar": "baz"
}

方案2:保留重复键(注意:不符合JSON规范)

JSON官方规范不允许对象存在重复键,但部分解析器(如Newtonsoft.Json)支持该写法。若确需实现,可通过转换器手动写入重复键:

public class NameValueCollectionDuplicateKeysConverter : JsonConverter<NameValueCollection>
{
    public override NameValueCollection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, NameValueCollection value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        foreach (string key in value.AllKeys)
        {
            if (key == null) continue;
            string[] values = value.GetValues(key);
            foreach (string val in values)
            {
                writer.WriteString(key, val);
            }
        }
        writer.WriteEndObject();
    }
}

将序列化方法中的转换器替换为此类,即可生成包含重复键的JSON,但需注意:这种输出可能导致严格遵循JSON规范的解析器报错,使用前需确认下游解析器支持该格式。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 03:57:38