Utf8Json自定义Int64StringConversionFormatter未被调用问题排查
我之前也碰到过类似的问题,结合Utf8Json在AspNetCore WebApi中的工作机制,给你梳理几个最可能的原因和解决办法:
1. 确认自定义Resolver是否关联到AspNetCore的格式化器
你虽然注册了CompositeResolver并设为默认,但AspNetCore的Utf8JsonInputFormatter和Utf8JsonOutputFormatter并不会自动绑定全局默认Resolver——必须在配置这两个格式化器时,显式传入自定义Resolver实例,否则它们会默认使用StandardResolver.Default,自然不会触发你的自定义实现。
正确的配置示例:
services.AddControllers(options => { // 先移除默认的System.Text.Json格式化器(避免冲突) options.InputFormatters.RemoveType<SystemTextJsonInputFormatter>(); options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>(); // 创建自定义CompositeResolver var customResolver = CompositeResolver.Create( new IJsonFormatter[] { new Int64StringConversionFormatter() }, new IJsonResolver[] { StandardResolver.Default }); // 添加Utf8Json格式化器并传入自定义Resolver options.InputFormatters.Add(new Utf8JsonInputFormatter( options, customResolver, ArrayPool<byte>.Shared, new JsonSerializerOptions())); options.OutputFormatters.Add(new Utf8JsonOutputFormatter( customResolver, ArrayPool<byte>.Shared, new JsonSerializerOptions())); });
2. 检查CompositeResolver的组合顺序
Utf8Json的Resolver是按顺序匹配格式化器的,如果把自定义格式化器放在默认Resolver之后,内置的long类型格式化器会先被匹配到,你的自定义实现就会被忽略。
正确的组合逻辑是:自定义格式化器优先级更高,其余类型 fallback 到默认Resolver:
var customResolver = CompositeResolver.Create( // 自定义格式化器放在最前面 new IJsonFormatter[] { new Int64StringConversionFormatter() }, // 其他类型用默认Resolver处理 new IJsonResolver[] { StandardResolver.Default });
3. 确认是否覆盖了Nullable类型
如果你的API模型里用的是long?(可空长整型),但自定义格式化器只实现了IJsonFormatter<long>,那可空类型会匹配不到你的逻辑,需要额外实现IJsonFormatter<long?>:
public class NullableInt64StringConversionFormatter : IJsonFormatter<long?> { private readonly Int64StringConversionFormatter _innerFormatter = new Int64StringConversionFormatter(); public long? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) return null; return _innerFormatter.Deserialize(ref reader, formatterResolver); } public void Serialize(ref JsonWriter writer, long? value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } _innerFormatter.Serialize(ref writer, value.Value, formatterResolver); } }
然后把这个新增的格式化器也加入CompositeResolver的数组中:
new IJsonFormatter[] { new Int64StringConversionFormatter(), new NullableInt64StringConversionFormatter() }
4. 验证AspNetCore确实使用了Utf8Json格式化器
有时候可能因为配置顺序问题,默认的System.Text.Json格式化器没有被完全移除,导致请求实际用的不是Utf8Json。你可以:
- 在请求头中指定
Accept: application/json - 调试时查看当前请求对应的格式化器类型,确认是
Utf8JsonInputFormatter/Utf8JsonOutputFormatter在处理
5. 检查自定义格式化器的实现逻辑
确保你的Int64StringConversionFormatter方法签名和逻辑正确,比如:
public class Int64StringConversionFormatter : IJsonFormatter<long> { public long Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { // 兼容字符串和数字类型的反序列化逻辑 if (reader.TokenType == JsonTokenType.String) { var strValue = reader.ReadString(); return long.Parse(strValue); } return reader.ReadInt64(); } public void Serialize(ref JsonWriter writer, long value, IJsonFormatterResolver formatterResolver) { // 序列化为字符串 writer.WriteString(value.ToString()); } }
可以给方法加断点或日志,确认是否真的没被调用——如果是逻辑报错导致的“看似没触发”,也能快速定位问题。
内容的提问来源于stack exchange,提问作者amiry jd

