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

如何在System.Text.Json的Converter中修改JsonSerializerOptions的WriteIndented行为

问题:System.Text.Json自定义Converter中WriteIndented设置不生效的解决方法

在使用System.Text.Json进行序列化时,自定义JsonConverter<Point>后,在Write方法中创建新的JsonSerializerOptions并设置WriteIndented = false,但该设置会被忽略,序列化结果仍保持缩进格式;同时设置的PropertyNamingPolicy却能正常生效。需要实现Converter内正确修改WriteIndented的行为。

复现代码

open System
open System.Text.Json
open System.Text.Json.Serialization

type Point = { x: int; y: int }

JsonSerializer.Serialize ({ x=3; y=4 })

type JsonConverterPointNotIndented () =
    inherit System.Text.Json.Serialization.JsonConverter<Point>()

    override _.Read (_, _, _) = raise <| NotImplementedException()

    override c.Write (writer, value, options) =

        let o = JsonSerializerOptions ()
        o.WriteIndented <- false // 该设置被忽略,仍会输出缩进格式
        o.PropertyNamingPolicy <- JsonNamingPolicy.SnakeCaseUpper // 此设置生效

        JsonSerializer.Serialize(writer, value, o)

let o = JsonSerializerOptions()
o.WriteIndented <- true
o.Converters.Add(JsonConverterPointNotIndented())
JsonSerializer.Serialize ({ x=3; y=4 }, o)

// 实际输出:
val it: string = "{
  "X": 3,
  "Y": 4
}"

// 期望输出:
val it: string = "{"X":3,"Y":4}"

问题原因

当在Converter的Write方法中调用JsonSerializer.Serialize(writer, value, o)时,传入的Utf8JsonWriter已经被外部的JsonSerializerOptions(设置了WriteIndented = true)初始化,writer自身的缩进状态已经开启。新创建的JsonSerializerOptions中的WriteIndented设置无法覆盖writer已有的状态,而PropertyNamingPolicy属于序列化逻辑配置,不受writer状态影响,因此能正常生效。

解决方法

方法1:直接修改Utf8JsonWriter的缩进状态(推荐)

在Write方法中临时修改writer的缩进属性,序列化完成后恢复原有状态,避免影响后续序列化逻辑:

type JsonConverterPointNotIndented () =
    inherit System.Text.Json.Serialization.JsonConverter<Point>()

    override _.Read (_, _, _) = raise <| NotImplementedException()

    override c.Write (writer, value, options) =
        // 保存writer原有缩进状态
        let originalIndentation = writer.Indentation
        let originalWriteIndented = writer.WriteIndented
        try
            // 设置为无缩进
            writer.WriteIndented <- false
            writer.Indentation <- 0
            
            let o = JsonSerializerOptions ()
            o.PropertyNamingPolicy <- JsonNamingPolicy.SnakeCaseUpper
            JsonSerializer.Serialize(writer, value, o)
        finally
            // 恢复原有状态
            writer.WriteIndented <- originalWriteIndented
            writer.Indentation <- originalIndentation

方法2:先序列化为字符串再写入writer

通过先将对象序列化为无缩进的字符串,再直接写入writer,这种方式不受外部writer状态影响,但会额外产生字符串对象,性能略逊于方法1:

type JsonConverterPointNotIndented () =
    inherit System.Text.Json.Serialization.JsonConverter<Point>()

    override _.Read (_, _, _) = raise <| NotImplementedException()

    override c.Write (writer, value, options) =
        let o = JsonSerializerOptions ()
        o.WriteIndented <- false
        o.PropertyNamingPolicy <- JsonNamingPolicy.SnakeCaseUpper
        // 先序列化为无缩进字符串
        let jsonStr = JsonSerializer.Serialize(value, o)
        // 直接写入原始JSON字符串
        writer.WriteRawValue(jsonStr)

效果验证

修改后,执行序列化代码会得到预期的无缩进结果:

val it: string = "{"X":3,"Y":4}"

内容的提问来源于stack exchange,提问作者citykid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:53:14