如何通过选项控制自定义JsonConverter在不同场景输出不同序列化结果
解决方案
核心思路
通过给自定义JsonConverter增加场景标识参数,配合易失字段标记属性,仅用一套Converter逻辑实现两种序列化场景的差异化处理,无需重复编码也不需要扩展密封的JsonSerializerOptions类。
步骤1:定义易失字段标记属性
首先新增一个空Attribute用于标记不需要持久化的易失字段:
[AttributeUsage(AttributeTargets.Property)] public class VolatileDataAttribute : Attribute { }
在设备实体类中给对应的易失字段加上该标记:
public class Device { public string Id { get; set; } public string Name { get; set; } // 标记为易失数据,持久化时忽略 [VolatileData] public int CurrentConnectionDelay { get; set; } [VolatileData] public bool IsOnline { get; set; } // 其他需要持久化的配置字段 public int UploadInterval { get; set; } }
步骤2:改造自定义JsonConverter
在你现有自定义JsonConverter的基础上,新增构造函数接收场景标识参数,序列化时根据标识判断是否跳过易失字段:
public class DeviceJsonConverter : JsonConverter<Device> { private readonly bool _isPersistenceScene; // 构造函数传入当前序列化场景标识 public DeviceJsonConverter(bool isPersistenceScene) { _isPersistenceScene = isPersistenceScene; } public override Device Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 反序列化逻辑两个场景完全复用,可直接保留你原有的自定义逻辑 return JsonSerializer.Deserialize<Device>(ref reader, options); } public override void Write(Utf8JsonWriter writer, Device value, JsonSerializerOptions options) { writer.WriteStartObject(); // 遍历设备所有属性 foreach (var property in typeof(Device).GetProperties()) { // 持久化场景下跳过标记了[VolatileData]的字段 if (_isPersistenceScene && Attribute.IsDefined(property, typeof(VolatileDataAttribute))) { continue; } // 其他字段正常序列化 var propValue = property.GetValue(value); writer.WritePropertyName(property.Name); JsonSerializer.Serialize(writer, propValue, property.PropertyType, options); } writer.WriteEndObject(); } }
步骤3:不同场景传入不同的Converter实例
仅需要实例化Converter时传入不同的标识参数,即可实现两个场景的差异化处理,完全不需要冗余代码:
- SignalR前端推送场景:序列化保留所有字段
// 配置SignalR的Json序列化选项 builder.Services.AddSignalR() .AddJsonProtocol(opt => { // 传入false表示当前是前端推送场景,不忽略易失字段 opt.PayloadSerializerOptions.Converters.Add(new DeviceJsonConverter(isPersistenceScene: false)); });
- 本地配置持久化场景:序列化忽略易失字段
// 本地持久化专用的序列化配置 var persistSerializeOptions = new JsonSerializerOptions { WriteIndented = true, // 传入true表示当前是持久化场景,自动忽略易失字段 Converters = { new DeviceJsonConverter(isPersistenceScene: true) } }; // 写入本地文件 var configJson = JsonSerializer.Serialize(deviceList, persistSerializeOptions); File.WriteAllText("./device_config.json", configJson);
可选优化
如果实体类字段较多、性能要求较高,可以搭配System.Text.Json的源生成序列化功能,提前生成序列化元数据,避免运行时反射遍历属性的性能损耗。
内容的提问来源于stack exchange,提问作者sutt
相关产品推荐
相关产品推荐

