C# JsonConvert反序列化后输出JSON时$type改type无效怎么办
问题根因
- 你在
DocumentData和DocumentField类的type属性上标注的[JsonProperty(PropertyName = "$type")]是双向映射规则:反序列化时会将输入JSON中的$type字段值绑定到该属性,但序列化输出时也会强制将该属性对应的JSON字段名输出为$type,和你预期输出type的需求直接冲突。 - 若你的序列化配置开启了
TypeNameHandling(非None值),Newtonsoft.Json会自动额外生成$type字段用于多态类型标识,会进一步导致输出不符合预期。
修复步骤
1. 修改实体类
删除DocumentData和DocumentField类中type属性上的[JsonProperty(PropertyName = "$type")]特性,核心实体代码修改后如下:
public class DocumentData { public string Name { get; set; } // 移除原[JsonProperty(PropertyName = "$type")]特性 public string type { get; set; } public List<DocumentField> Fields { get; set; } } public class DocumentField { public string Name { get; set; } // 移除原[JsonProperty(PropertyName = "$type")]特性 public string type { get; set; } public string SuspiciousSymbols { get; set; } public string RecognizedValue { get; set; } public string Value { get; set; } }
2. 调整反序列化逻辑
去掉特性后,直接反序列化无法读取输入JSON中$type字段的值,可根据业务场景选择以下两种处理方式:
轻量场景(值中不会出现"$type"字符串)
直接替换JSON文本中的键名,实现成本最低:
// 将输入JSON中所有键名$type替换为type,匹配实体属性名 string processedJson = jsonText.Replace("\"$type\"", "\"type\""); DocumentDTO documentResult = JsonConvert.DeserializeObject<DocumentDTO>(processedJson);
严谨场景(避免误替换值内容)
通过JObject递归遍历节点替换键名,不会影响字段值中出现的$type文本:
JObject jsonObj = JObject.Parse(jsonText); ReplaceJsonKey(jsonObj, "$type", "type"); DocumentDTO documentResult = jsonObj.ToObject<DocumentDTO>(); // 递归替换键名的辅助方法 void ReplaceJsonKey(JToken token, string oldKey, string newKey) { if (token.Type == JTokenType.Object) { JObject obj = (JObject)token; foreach (var prop in obj.Properties().ToList()) { if (prop.Name == oldKey) { obj.Add(newKey, prop.Value); prop.Remove(); } ReplaceJsonKey(prop.Value, oldKey, newKey); } } else if (token.Type == JTokenType.Array) { foreach (var item in (JArray)token) { ReplaceJsonKey(item, oldKey, newKey); } } }
3. 配置接口全局序列化规则
必须关闭Newtonsoft.Json自动生成类型元数据的配置,同时匹配你期望的小驼峰输出格式:
- 若使用ASP.NET Web API 2,在
WebApiConfig.cs中修改JSON格式化器配置:
config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings { // 完全关闭自动类型元数据输出,禁止自动生成$type字段 TypeNameHandling = TypeNameHandling.None, // 配置小驼峰命名,匹配version、documents等输出格式要求 ContractResolver = new CamelCasePropertyNamesContractResolver() };
- 若使用ASP.NET Core + Newtonsoft.Json,在服务注册阶段添加如下配置:
builder.Services.AddControllers() .AddNewtonsoftJson(options => { options.SerializerSettings.TypeNameHandling = TypeNameHandling.None; options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); });
效果验证
以上配置完成后,接口序列化输出时type属性会正常输出为type字段,不会再出现$type字段,和你给出的预期返回结果完全一致。
内容的提问来源于stack exchange,提问作者core_user
相关产品推荐
相关产品推荐

