You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过选项控制自定义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时传入不同的标识参数,即可实现两个场景的差异化处理,完全不需要冗余代码:

  1. SignalR前端推送场景:序列化保留所有字段
// 配置SignalR的Json序列化选项
builder.Services.AddSignalR()
    .AddJsonProtocol(opt =>
    {
        // 传入false表示当前是前端推送场景,不忽略易失字段
        opt.PayloadSerializerOptions.Converters.Add(new DeviceJsonConverter(isPersistenceScene: false));
    });
  1. 本地配置持久化场景:序列化忽略易失字段
// 本地持久化专用的序列化配置
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 15:24:04