如何使Utf8Json的NullStringJsonFormatter全局生效无需属性注解?
解决Utf8Json自定义Null字符串格式化器全局生效问题
问题分析
你已经实现了NullStringJsonFormatter,通过属性注解[JsonFormatter(typeof(NullStringJsonFormatter))]可以正常将字符串"null"反序列化为null,但全局注册到CompositeResolver后未生效,而StandardResolver.ExcludeNull功能正常。这通常是因为自定义格式化器的注册顺序或Resolver构建方式不正确,导致StandardResolver的默认string格式化器优先级更高,覆盖了你的自定义实现。
正确实现步骤
1. 确保自定义格式化器逻辑正确
先确认你的NullStringJsonFormatter完整实现了序列化和反序列化逻辑,覆盖所有边界情况:
public class NullStringJsonFormatter : IJsonFormatter<string> { public void Serialize(ref JsonWriter writer, string value, IJsonFormatterResolver resolver) { if (value == null || value.Equals("null", StringComparison.OrdinalIgnoreCase)) { writer.WriteNull(); return; } writer.WriteString(value); } public string Deserialize(ref JsonReader reader, IJsonFormatterResolver resolver) { if (reader.GetCurrentJsonToken() == JsonToken.Null) { reader.ReadNext(); return null; } var rawString = reader.ReadString(); return rawString.Equals("null", StringComparison.OrdinalIgnoreCase) ? null : rawString; } }
2. 构建自定义Resolver并全局注册
要让自定义格式化器全局生效,需要创建一个专门的Resolver来托管它,并确保在CompositeResolver中优先于StandardResolver被调用:
方式一:自定义Resolver类
public class NullStringResolver : IJsonFormatterResolver { // 单例实例避免重复创建 public static readonly NullStringResolver Instance = new NullStringResolver(); public IJsonFormatter<T> GetFormatter<T>() { // 仅对string类型返回自定义格式化器,其他类型交给后续Resolver处理 return FormatterCache<T>.Formatter; } // 静态缓存类提升性能 private static class FormatterCache<T> { public static readonly IJsonFormatter<T> Formatter = typeof(T) == typeof(string) ? (IJsonFormatter<T>)new NullStringJsonFormatter() : null; } }
然后组合Resolver并全局设置:
// 组合自定义Resolver和带ExcludeNull的StandardResolver,自定义Resolver放在前面 var globalResolver = CompositeResolver.Create( NullStringResolver.Instance, StandardResolver.ExcludeNull ); // 全局设置默认Resolver JsonSerializer.SetDefaultResolver(globalResolver);
方式二:直接传入格式化器列表
如果不想单独写Resolver类,也可以直接将自定义格式化器传入CompositeResolver.Create:
var globalResolver = CompositeResolver.Create( new IJsonFormatter[] { new NullStringJsonFormatter() }, new[] { StandardResolver.ExcludeNull } ); JsonSerializer.SetDefaultResolver(globalResolver);
3. 验证效果
用你的测试JSON验证:
public class TestModel { public string Info { get; set; } public string Name { get; set; } } // 测试JSON var json = @"{""info"":""null"", ""name"":""example""}"; var model = JsonSerializer.Deserialize<TestModel>(json); // 此时model.Info应为null,model.Name为"example"
关键注意事项
- 注册顺序:在
CompositeResolver中,自定义Resolver/格式化器必须放在StandardResolver前面,因为Utf8Json会按顺序查找第一个匹配的格式化器。 - 类型覆盖:确保自定义Resolver只针对
string类型返回格式化器,避免影响其他类型的序列化逻辑。 - 全局生效范围:调用
JsonSerializer.SetDefaultResolver后,所有未指定特定Resolver的序列化/反序列化操作都会使用这个全局配置,无需再给每个属性加注解。
内容的提问来源于stack exchange,提问作者z z
相关产品推荐
相关产品推荐

