語言
本文說明如何使用 Type 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)
重複使用寫入器
從 .NET 11 開始,請呼叫 Reset(Stream, JsonWriterOptions) 或 Reset(IBufferWriter<Byte>, JsonWriterOptions) 來重複使用寫入器。 這些多載會變更目的地和選項,而不會配置另一個 Utf8JsonWriter。
在重置寫入器之前,請先完成目前的 JSON 承載資料,並呼叫 Flush。
Reset 會清除寫入器狀態,且不會排清待處理的輸出:
writer.WriteEndObject();
writer.Flush();
writer.Reset(nextStream, new JsonWriterOptions { Indented = true });
writer.WriteEndObject()
writer.Flush()
writer.Reset(nextStream, New JsonWriterOptions With {.Indented = True})
使用 UTF-8 文字書寫
為了在使用 Utf8JsonWriter時達到最佳效能,請將 JSON payload 寫入已編碼為 UTF-8 文字,而非 UTF-16 字串。 用 JsonEncodedText 來快取並預先編碼已知字串屬性名稱和值為靜態,然後傳給寫入者,而不是使用 UTF-16 字串字面量。 這比快取並使用 UTF-8 位元組陣列還要快。
如果你需要自訂逃脫,這種方法也適用。
System.Text.Json 寫字串時不允許關閉跳脫功能。 不過,你可以將自己自訂的 JavaScriptEncoder 作為選項傳給寫入器,或者建立你自己的 JsonEncodedText,使用你的 JavascriptEncoder 來進行逸出處理,然後寫入 JsonEncodedText,而不是字串。 欲了解更多資訊,請參閱 自訂字元編碼。
撰寫原始 JSON
在某些情況下,你可能會想把「原始」的 JSON 寫入你正在建立的 Utf8JsonWriterJSON payload。 你可以用 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 // } // ] //}
自訂角色逃脫
StringEscapeHandling 設定JsonTextWriter提供逃逸所有非 ASCII 字元或 HTML 字元的選項。 預設情況下, Utf8JsonWriter 跳脫所有非 ASCII 及 HTML 字元。 這項逸出處理是基於縱深防禦的安全考量而進行的。 若要指定不同的逸出原則,請建立 JavaScriptEncoder,並設定 JsonWriterOptions.Encoder。 欲了解更多資訊,請參閱 自訂字元編碼。
寫入空值
若要使用 Utf8JsonWriter 寫入空值,請呼叫:
- WriteNull 以 null 作為值寫入鍵值組。
- WriteNullValue 將 null 寫成 JSON 陣列的元素。
對於字串性質,若字串為零 WriteString ,則 與 WriteStringValue 等價於 WriteNull 和 WriteNullValue。
撰寫 Timespan、URI 或 char 值
要寫入 Timespan,Urichar或值,將它們格式化為字串(例如呼叫 ToString(),並呼叫 WriteStringValue)。