共用方式為


如何在 System.Text.Json 中使用 Utf8JsonWriter

本文說明如何使用 Utf8JsonWriter 類型來建置自訂序列化程式。

Utf8JsonWriter 是一種高效能方式,可從常見的 .NET 類型 (例如 StringInt32DateTime) 撰寫 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 文字的 JSON 承載,而非 UTF-16 字串。 使用 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
    //    }
    //  ]
    //}
    

自訂字元逸出

JsonTextWriterStringEscapeHandling 設定提供逸出所有非 ASCII 字元 HTML 字元的選項。 根據預設,Utf8JsonWriter 會逸出所有非 ASCII HTML 字元。 此逸出是為了深層防禦安全性理由而進行的。 若要指定不同的逸出原則,請建立 JavaScriptEncoder 並設定 JsonWriterOptions.Encoder。 如需詳細資訊,請參閱自訂字元編碼

撰寫 null 值

若要使用 Utf8JsonWriter 撰寫 null 值,請呼叫:

  • WriteNull 以將機碼值組寫入 null 作為值。
  • WriteNullValue 以將 null 寫入為 JSON 陣列的元素。

針對字串屬性,如果字串為 null,則 WriteStringWriteStringValue 相當於 WriteNullWriteNullValue

撰寫 Timespan、URI 或 char 值

若要撰寫 TimespanUri、或 char 值,請將其格式化為字串 (例如藉由呼叫 ToString()) 並呼叫 WriteStringValue

另請參閱