如何在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
相关产品推荐
相关产品推荐

