自定义JSON转换器脱敏后序列化返回空字符串问题排查
问题分析与解决方案
你的代码返回空字符串的核心原因是无限递归调用导致序列化失败,另外还有一个需要注意的副作用问题,我来逐一拆解并给出修复方案:
核心问题:无限递归引发的序列化异常
在你的WriteJson方法中,你先调用了writer.WriteStartObject(),接着又调用serializer.Serialize(writer, value)。由于你已经将StudentJsonConverter注册到了序列化设置中,且CanConvert方法明确表示它可以处理Student类型,所以serializer.Serialize会再次触发当前转换器的WriteJson方法,形成无限递归。Json.NET在处理这种递归时会出现内部错误,最终返回空字符串作为失败结果。
另外,你直接修改了传入的student.Phone属性,这会改变原对象的内存状态——后续再使用这个Student实例时,它的Phone已经是脱敏后的值,这通常不是脱敏逻辑的预期行为(我们应该只在序列化输出中脱敏,不影响原对象)。
修复方案
这里提供两种可行的修复方式,你可以根据需求选择:
方案一:手动序列化所有属性(推荐,更可控)
直接手动写出每个属性的序列化逻辑,避免触发递归调用:
public class StudentJsonConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value is not Student student) { // 非Student类型回退到默认序列化 serializer.Serialize(writer, value); return; } writer.WriteStartObject(); // 序列化Name属性 writer.WritePropertyName(nameof(Student.Name)); serializer.Serialize(writer, student.Name); // 脱敏后序列化Phone属性 writer.WritePropertyName(nameof(Student.Phone)); var maskedPhone = MaskString(student.Phone); serializer.Serialize(writer, maskedPhone); writer.WriteEndObject(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } public override bool CanConvert(Type objectType) => typeof(Student) == objectType; private static string MaskString(string sensitiveInformation) => string.IsNullOrWhiteSpace(sensitiveInformation) ? null : new string('*', sensitiveInformation.Length); }
方案二:使用不包含当前转换器的新序列化器
创建一个不包含StudentJsonConverter的新JsonSerializer实例,用来序列化脱敏后的对象副本,避免递归:
public class StudentJsonConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value is not Student student) { serializer.Serialize(writer, value); return; } // 创建对象副本,避免修改原对象 var serializedStudent = new Student { Name = student.Name, Phone = MaskString(student.Phone) }; // 创建新的序列化器,排除当前转换器,避免递归 var newSerializer = new JsonSerializer { ReferenceLoopHandling = serializer.ReferenceLoopHandling, // 可以复制原序列化器的其他设置 }; newSerializer.Serialize(writer, serializedStudent); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } public override bool CanConvert(Type objectType) => typeof(Student) == objectType; private static string MaskString(string sensitiveInformation) => string.IsNullOrWhiteSpace(sensitiveInformation) ? null : new string('*', sensitiveInformation.Length); }
验证效果
使用你的调用代码测试修复后的转换器,会得到正确的序列化结果:
{"Name":"name","Phone":"****"}
内容的提问来源于stack exchange,提问作者Buda Gavril
相关产品推荐
相关产品推荐

