C#反序列化含内嵌大括号字符串的JSON时Data字段解析异常处理
问题根因
反序列化失败和Data属性的类型、[JsonIgnore]配置没有任何关系。核心问题是上游返回的JSON本身不符合RFC 8259语法规范:
标准JSON要求字符串值内部的双引号必须加反斜杠转义,但你收到的payload里Data字段是被双引号包裹的JSON片段,片段内部的双引号完全未做转义。JSON解析器读到Data值的开头双引号后,遇到{后第一个未转义的双引号(即Employee_ID字段前的引号)就会判定当前字符串已结束,后续内容直接触发词法解析错误——这个阶段发生在属性匹配逻辑之前,所以任何针对实体类属性的特性配置都不会生效。
可行解决方案
方案1:不需要使用Data字段时的最快修复(兼容所有JSON序列化库)
不需要折腾序列化器配置,直接对原始JSON字符串做预处理修复语法即可,性能开销极低,完全满足你不需要读取Data内容的需求:
using System.Text.RegularExpressions; // 读取到的原始JSON响应字符串 string rawJson = await httpClient.GetStringAsync(requestUrl); // 正则匹配非法格式的Data字段,替换为合法的null值 string fixedJson = Regex.Replace( rawJson, @"""Data""\s*:\s*""\{.*?\}"",", "\"Data\":null,", RegexOptions.Singleline ); // 后续走正常反序列化逻辑即可,[JsonIgnore]特性也能正常生效 var result = JsonSerializer.Deserialize<OutsideEvent>(fixedJson);
方案2:需要解析Data字段内容的处理方式
如果你后续需要用到Data内的员工信息,可以根据你使用的序列化库做配置,直接将嵌套内容映射为强类型对象:
适配Newtonsoft.Json(Json.NET)
- 修改实体类,将
Data属性改为强类型,添加自定义转换器:
public class OutsideEvent { public string Event_Id { get; set; } public string Event_Name { get; set; } // 注意:原int类型存在时间戳溢出风险,建议改为long兼容13位毫秒级时间戳 public long Event_DateTime { get; set; } public string ClientCode { get; set; } public string Resource_Field { get; set; } public object Resource_Identifier { get; set; } public object Object { get; set; } public string? Object_Identifier { get; set; } [JsonConverter(typeof(NestedJsonConverter<eventData>))] public eventData? Data { get; set; } public string Endpoint { get; set; } public string EndpointUrl { get; set; } }
- 实现自定义转换器,处理嵌套JSON的二次解析:
public class NestedJsonConverter<T> : JsonConverter<T> { public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer) { string rawContent = reader.ReadAsString(); return string.IsNullOrWhiteSpace(rawContent) ? default : JsonConvert.DeserializeObject<T>(rawContent); } public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer) { writer.WriteValue(JsonConvert.SerializeObject(value)); } }
- 反序列化时开启容错配置:
var settings = new JsonSerializerSettings { CheckAdditionalContent = false, Error = (sender, args) => { if (args.ErrorContext.Path == nameof(OutsideEvent.Data)) args.ErrorContext.Handled = true; } }; var result = JsonConvert.DeserializeObject<OutsideEvent>(rawJson, settings);
适配.NET默认System.Text.Json
- 实体类修改逻辑和上述一致,添加对应版本的自定义转换器:
public class NestedJsonConverterSTJ<T> : JsonConverter<T> { public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); string rawContent = doc.RootElement.GetRawText().Trim('"'); return string.IsNullOrWhiteSpace(rawContent) ? default : JsonSerializer.Deserialize<T>(rawContent, options); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { writer.WriteStringValue(JsonSerializer.Serialize(value, options)); } }
- 反序列化时开启宽松解析配置:
var options = new JsonSerializerOptions { AllowTrailingCommas = true, ReadCommentHandling = JsonCommentHandling.Skip, Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; var result = JsonSerializer.Deserialize<OutsideEvent>(rawJson, options);
内容的提问来源于stack exchange,提问作者Rich
相关产品推荐
相关产品推荐

