如何用[JsonExtensionData]与JsonNamingPolicy.CamelCase正确序列化Dictionary?
System.Text.Json中[JsonExtensionData]字典键未应用驼峰命名的问题
我需要使用JsonNamingPolicy.CamelCase序列化对象,但在将Dictionary与[JsonExtensionData]属性配合使用时,扩展数据的键未被转为驼峰格式,不符合预期。
示例代码
public class Test { public Dictionary<string, object> Labels { get; set; } = new(); [JsonExtensionData] public Dictionary<string, object> MetaInfo { get; set; } = new(); public Dictionary<string, object>? Nullable { get; set; } = null; } public class TestContent { public string? Value { get; set; } }
System.Text.Json 配置
var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, }; var test = new Test { Labels = new Dictionary<string, object> { { "Test1", new TestContent{ Value = "TestContent1" } }, { "Test2", new TestContent { Value = null } }, }, MetaInfo = new Dictionary<string, object> { { "Test1", new TestContent{ Value = "TestContent1" } }, { "Test2", new TestContent { Value = null } }, } }; var result = JsonSerializer.Serialize(test, options); System.Console.WriteLine(result);
预期输出
扩展数据的键应转为驼峰格式(test1、test2):
{ "labels":{ "test1":{ "value": "TestContent1" }, "test2":{ } }, "test1":{ "value": "TestContent1" }, "test2":{ } }
实际输出
扩展数据的键仍为原格式(Test1、Test2):
{ "labels":{ "test1":{ "value": "TestContent1" }, "test2":{ } }, "Test1":{ "value": "TestContent1" }, "Test2":{ } }
可见JsonNamingPolicy.CamelCase对labels生效,但对扩展数据的键不生效。切换为Newtonsoft.Json时可正常生成驼峰格式的键:
var contractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, ProcessExtensionDataNames = true, OverrideSpecifiedNames = false, } }; var settings = new JsonSerializerSettings { ContractResolver = contractResolver, NullValueHandling = NullValueHandling.Ignore, }; var result = JsonConvert.SerializeObject(test, settings); System.Console.WriteLine(result); // {"labels":{"test1":{"value":"TestContent1"},"test2":{}},"test1":{"value":"TestContent1"},"test2":{}}
请问我是否遗漏了某些设置?
解决方案
这是System.Text.Json与Newtonsoft.Json的默认行为差异:System.Text.Json默认不会对标记了[JsonExtensionData]的字典键应用命名策略,即使配置了DictionaryKeyPolicy也不会生效。
1. .NET 7及以上版本
直接在JsonSerializerOptions中新增ExtensionDataNamingPolicy配置即可,这是.NET 7新增的专门针对扩展数据的命名策略选项:
var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, ExtensionDataNamingPolicy = JsonNamingPolicy.CamelCase // 新增此配置 };
2. .NET 6及以下版本
需要自定义JsonConverter来处理扩展数据的键转换:
首先创建转换器:
public class CamelCaseExtensionDataConverter : JsonConverter<Dictionary<string, object>> { private readonly JsonNamingPolicy _camelCasePolicy = JsonNamingPolicy.CamelCase; public override Dictionary<string, object>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 反序列化时可根据需求将驼峰键转回原格式,此处按默认逻辑处理 var dict = JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options); return dict?.ToDictionary(kv => _camelCasePolicy.ConvertName(kv.Key), kv => kv.Value); } public override void Write(Utf8JsonWriter writer, Dictionary<string, object> value, JsonSerializerOptions options) { foreach (var kvp in value) { var camelCaseKey = _camelCasePolicy.ConvertName(kvp.Key); writer.WritePropertyName(camelCaseKey); JsonSerializer.Serialize(writer, kvp.Value, options); } } }
然后在MetaInfo属性上标记转换器:
[JsonExtensionData] [JsonConverter(typeof(CamelCaseExtensionDataConverter))] public Dictionary<string, object> MetaInfo { get; set; } = new();
或者在JsonSerializerOptions中全局注册转换器(适用于多个类有扩展数据需要处理的场景):
options.Converters.Add(new CamelCaseExtensionDataConverter());
完成以上配置后,扩展数据的键即可转为驼峰格式,与预期输出一致。
内容的提问来源于stack exchange,提问作者Changemyminds
相关产品推荐
相关产品推荐

