Поделиться через


Использование Utf8JsonWriter в System.Text.Json

В этой статье показано, как использовать Utf8JsonWriter тип для создания пользовательских сериализаторов.

Utf8JsonWriter — это высокопроизводительный способ записать текст JSON в кодировке UTF-8 из распространенных типов .NET, например String, Int32 и DateTime. Модуль записи — это низкоуровневый тип, с помощью которого можно создавать пользовательские сериализаторы. Метод 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 записывайте полезные данные JSON, уже закодированные как текст UTF-8, а не как строки UTF-16. Используйте JsonEncodedText, чтобы кэшировать и предварительно закодировать известные имена и значения свойств строки как статические, а затем передать их в модуль записи вместо использования строковых литералов UTF-16. Это быстрее, чем кэширование и использование байтовых массивов UTF-8.

Этот подход также работает, если необходимо выполнить пользовательское экранирование. System.Text.Json не позволяет отключить экранирование при записи строки. Однако можно передать собственный пользовательский JavaScriptEncoder в качестве параметра для модуля записи или создать собственный JsonEncodedText, который использует JavascriptEncoder для выполнения экранирования, а затем написать JsonEncodedText вместо строки. Дополнительные сведения см. в статье Настройка кодировки символов.

Запись необработанного JSON

В некоторых сценариях может потребоваться записать "необработанный" JSON в полезные данные JSON, с помощью которого вы создаете Utf8JsonWriter. Это можно использовать 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
    //    }
    //  ]
    //}
    

Настройка экранирования символов

Параметр StringEscapeHandlingJsonTextWriter предлагает варианты для экранирования всех символов, не являющихся символами ASCII, или символов HTML. По умолчанию Utf8JsonWriter экранирует все символы, отличные от ASCII, и символы HTML. Такое экранирование выполняется в целях глубокой защиты. Чтобы указать другую политику экранирования, создайте JavaScriptEncoder и задайте JsonWriterOptions.Encoder. Дополнительные сведения см. в статье Настройка кодировки символов.

Запись значений NULL

Чтобы записать значения NULL с помощью Utf8JsonWriter, вызовите:

  • WriteNull для записи пары "ключ-значение" со значением NULL.
  • WriteNullValue для записи значения NULL в качестве элемента массива JSON.

Для строкового свойства, если строка имеет значение NULL, WriteString и WriteStringValue эквивалентны WriteNull и WriteNullValue.

Запись значений TimeSpan, URI или char

Для записи или Urichar значений отформатируйте Timespanих как строки (например, вызовToString()) и вызовWriteStringValue.

См. также