如何在 System.Text.Json 中使用 Utf8JsonWriter
本文介绍如何使用 Utf8JsonWriter 类型生成自定义序列化程序。
Utf8JsonWriter 是一种高性能方式,从常见 .NET 类型(例如,String
、Int32
和 DateTime
)编写 UTF-8 编码的 JSON 文本。 该编写器是一种低级类型,可用于生成自定义序列化程序。 JsonSerializer.Serialize 方法在后台使用 Utf8JsonWriter
。
下面的示例演示如何使用 Utf8JsonWriter 类:
var options = new JsonWriterOptions
{
Indented = true
};
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream, options);
writer.WriteStartObject();
writer.WriteString("date", DateTimeOffset.UtcNow);
writer.WriteNumber("temp", 42);
writer.WriteEndObject();
writer.Flush();
string json = Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(json);
Dim options As JsonWriterOptions = New JsonWriterOptions With {
.Indented = True
}
Dim stream As MemoryStream = New MemoryStream
Dim writer As Utf8JsonWriter = New Utf8JsonWriter(stream, options)
writer.WriteStartObject()
writer.WriteString("date", DateTimeOffset.UtcNow)
writer.WriteNumber("temp", 42)
writer.WriteEndObject()
writer.Flush()
Dim json As String = Encoding.UTF8.GetString(stream.ToArray())
Console.WriteLine(json)
使用 UTF-8 文本进行编写
若要在使用 Utf8JsonWriter
时实现可能的最佳性能,请编写已编码为 UTF-8 文本(而不是 UTF-16 字符串)的 JSON 有效负载。 使用 JsonEncodedText 可缓存已知字符串属性名称和值并预先编码为静态,并将这些内容传递给编写器,而不是使用 UTF-16 字符串文本。 这比缓存并使用 UTF-8 字节数组更快。
如果需要进行自定义转义,此方法也适用。 System.Text.Json
不允许在编写字符串时禁用转义。 但是,可以将自己的自定义 JavaScriptEncoder 作为一个选项传入编写器,或创建自己的 JsonEncodedText
以使用你的 JavascriptEncoder
进行转义,然后编写 JsonEncodedText
而不是字符串。 有关详细信息,请参阅自定义字符编码。
写入原始 JSON
在某些情况下,可能需要将“原始”JSON 写入使用 Utf8JsonWriter
创建的 JSON 有效负载。 可使用 Utf8JsonWriter.WriteRawValue 执行此操作。 下面是典型场景:
你有一个要包含在新 JSON 中的现有 JSON 有效负载。
你想要将值的格式设置与默认格式
Utf8JsonWriter
不同。例如,你可能想要自定义数字格式设置。 默认情况下,System.Text.Json 会省略整数的小数点,例如写入
1
而不是1.0
。 基本原理是编写更少的字节会提高性能。 但是,假设 JSON 的使用者将带小数的数字视为双精度值,将不带小数的数字视为整数。 你可能希望通过写入整数的小数部分和零,确保数组中的数字全部被识别为双精度值。 下面的示例演示如何执行此操作:using System.Text; using System.Text.Json; namespace WriteRawJson; public class Program { public static void Main() { JsonWriterOptions writerOptions = new() { Indented = true, }; using MemoryStream stream = new(); using Utf8JsonWriter writer = new(stream, writerOptions); writer.WriteStartObject(); writer.WriteStartArray("defaultJsonFormatting"); foreach (double number in new double[] { 50.4, 51 }) { writer.WriteStartObject(); writer.WritePropertyName("value"); writer.WriteNumberValue(number); writer.WriteEndObject(); } writer.WriteEndArray(); writer.WriteStartArray("customJsonFormatting"); foreach (double result in new double[] { 50.4, 51 }) { writer.WriteStartObject(); writer.WritePropertyName("value"); writer.WriteRawValue( FormatNumberValue(result), skipInputValidation: true); writer.WriteEndObject(); } writer.WriteEndArray(); writer.WriteEndObject(); writer.Flush(); string json = Encoding.UTF8.GetString(stream.ToArray()); Console.WriteLine(json); } static string FormatNumberValue(double numberValue) { return numberValue == Convert.ToInt32(numberValue) ? numberValue.ToString() + ".0" : numberValue.ToString(); } } // output: //{ // "defaultJsonFormatting": [ // { // "value": 50.4 // }, // { // "value": 51 // } // ], // "customJsonFormatting": [ // { // "value": 50.4 // }, // { // "value": 51.0 // } // ] //}
自定义字符转义
JsonTextWriter
的 StringEscapeHandling 设置提供用于转移所有非 ASCII 字符或 HTML 字符的选项。 默认情况下,Utf8JsonWriter
会转义所有非 ASCII 和 HTML 字符。 进行此转义是出于深度防御安全原因。 若要指定不同的转义策略,请创建 JavaScriptEncoder 并设置 JsonWriterOptions.Encoder。 有关详细信息,请参阅自定义字符编码。
编写 null 值
若要使用 Utf8JsonWriter
编写 null 值,请调用:
- WriteNull,用于将具有 null 的键值对编写为值。
- WriteNullValue用于将 null 编写为 JSON 数组的元素。
对于字符串属性,如果字符串为 null,则 WriteString 和 WriteStringValue 等效于 WriteNull
和 WriteNullValue
。
编写 Timespan、Uri 或 char 值
若要写入 Timespan
、Uri
或 char
值,请将这些值格式化为字符串(例如,通过调用 ToString()
)并调用 WriteStringValue。