如何仅对字符串Token执行JsonConverter避免JSON.NET反序列化死循环
问题根源
你遇到的无限循环是因为调用serializer.Deserialize时,序列化器会优先使用已注册的ReferenceJsonConverter处理NamedType类型,就算当前Token是对象类型也会再次进入你的Converter逻辑,形成递归死循环。
可行解决方案
这里提供两种可直接落地的实现,优先推荐第一种,无并发风险:
方案1:创建无当前Converter的独立序列化器反序列化对象
在遇到非字符串Token时,先加载当前节点为JToken,再使用拷贝了原序列化器所有配置、但移除了ReferenceJsonConverter的新序列化器来反序列化,避免触发当前Converter:
public class ReferenceJsonConverter : JsonConverter<NamedType> { private readonly ContentLoader _contentLoader; public ReferenceJsonConverter(ContentLoader contentLoader) { _contentLoader = contentLoader; } public override bool CanWrite => false; public override void WriteJson(JsonWriter writer, NamedType value, JsonSerializer serializer) { throw new NotImplementedException(); } public override NamedType ReadJson(JsonReader reader, Type objectType, NamedType existingValue, bool hasExistingValue, JsonSerializer serializer) { JToken token = JToken.Load(reader); // 字符串类型走引用加载逻辑 if (token.Type == JTokenType.String) { string value = token.Value<string>().ToLower(); return _contentLoader.Load<NamedType>(value); } // 非字符串类型使用默认反序列化,新序列化器不加入当前Converter避免循环 var newSerializer = new JsonSerializer(); // 同步原有序列化器的所有配置和其他Converter foreach (var converter in serializer.Converters.Where(c => c != this)) { newSerializer.Converters.Add(converter); } newSerializer.ContractResolver = serializer.ContractResolver; newSerializer.Formatting = serializer.Formatting; newSerializer.NullValueHandling = serializer.NullValueHandling; newSerializer.DefaultValueHandling = serializer.DefaultValueHandling; // 其他你用到的自定义序列化配置可按需同步 return token.ToObject<NamedType>(newSerializer); } }
方案2:临时禁用当前Converter(仅单线程场景可用)
如果你的序列化器是单线程独占使用的,可以临时把当前Converter从集合中移除,反序列化完成后再加回来:
public override NamedType ReadJson(JsonReader reader, Type objectType, NamedType existingValue, bool hasExistingValue, JsonSerializer serializer) { switch (reader.TokenType) { case JsonToken.String: { string value = reader.Value!.ToString().ToLower(); return _contentLoader.Load<NamedType>(value); } default: { serializer.Converters.Remove(this); try { return (NamedType?) serializer.Deserialize(reader, objectType); } finally { serializer.Converters.Add(this); } } } }
效果验证
两种方案都完全符合你的需求:
- 当
NamedType类型的字段值为字符串时,走自定义引用加载逻辑 - 当
NamedType类型的字段值为JSON对象时,走默认反序列化流程,不会触发无限循环
内容的提问来源于stack exchange,提问作者Big_Bad_E
相关产品推荐
相关产品推荐

