使用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
相关产品推荐
相关产品推荐

