Cómo usar Utf8JsonWriter en System.Text.Json

En este artículo se explica cómo usar el tipo Utf8JsonWriter para crear serializadores personalizados.

Utf8JsonWriter ofrece una forma de escribir texto JSON con codificación UTF-8 de alto rendimiento a partir de tipos de .NET comunes como String, Int32 y DateTime. El escritor es un tipo de bajo nivel que se puede usar para compilar serializadores personalizados. El método JsonSerializer.Serialize usa Utf8JsonWriter en segundo plano.

En el siguiente ejemplo, se muestra cómo utilizar la clase 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)

Escritura con texto UTF-8

Para lograr el mejor rendimiento posible mientras usa Utf8JsonWriter, escriba cargas de JSON ya codificadas como texto UTF-8 en lugar de como cadenas UTF-16. Utilice JsonEncodedText para almacenar en caché y codificar previamente los nombres y valores de las propiedades de cadena conocidas como estáticos y pasarlos al escritor, en lugar de usar literales de cadena UTF-16. Esto es más rápido que el almacenamiento en caché y el uso de matrices de bytes UTF-8.

Este enfoque también funciona si necesita realizar un escape personalizado. System.Text.Json no permite deshabilitar el escape mientras se escribe una cadena, pero podría pasar su propio JavaScriptEncoder personalizado como una opción al escritor, o crear su propio JsonEncodedText que use su JavascriptEncoder para realizar el escape y, después, escribir el JsonEncodedText en lugar de la cadena. Para más información, vea Personalización de la codificación de caracteres.

Escritura de JSON sin formato

En algunos escenarios, es posible que quiera escribir JSON "sin formato" en una carga JSON que esté creando con Utf8JsonWriter. Puede usar Utf8JsonWriter.WriteRawValue para ello. Estos son escenarios típicos:

  • Tiene una carga JSON existente que quiere incluir en nuevo JSON.

  • Quiere aplicar un formato diferente al predeterminado Utf8JsonWriter a los valores.

    Por ejemplo, puede que quiera personalizar el formato de número. De manera predeterminada, System.Text.Json omite el separador decimal de los números enteros, escribiendo 1 en lugar de 1.0, por ejemplo. La lógica es que escribir menos bytes es bueno para el rendimiento. Pero imagine que el consumidor de JSON trata los números con decimales como valores double y los números sin decimales como enteros. Es posible que quiera asegurarse de que todos los números de una matriz se reconozcan como valores double escribiendo un separador decimal y cero para los números enteros. En el siguiente ejemplo se muestra cómo hacerlo:

    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
    //    }
    //  ]
    //}
    

Personalización del escape de caracteres

El valor StringEscapeHandling de JsonTextWriter ofrece opciones para escapar todos los caracteres que no sean ASCII o caracteres HTML. De forma predeterminada, Utf8JsonWriter convierte todos los caracteres que no son ASCII y HTML. Este escape se hace por motivos de seguridad de defensa en profundidad. Para especificar una directiva de escape diferente, cree un JavaScriptEncoder y configure JsonWriterOptions.Encoder. Para más información, vea Personalización de la codificación de caracteres.

Escritura de valores NULL

Para escribir valores NULL mediante Utf8JsonWriter, llame a:

  • WriteNull para escribir un par clave-valor con NULL como valor.
  • WriteNullValue para escribir NULL como un elemento de una matriz JSON.

En el caso de una propiedad de cadena, si la cadena es NULL, WriteString y WriteStringValue son equivalentes a WriteNull y WriteNullValue.

Escritura de valores TimeSpan, URI o char

Para escribir valores Timespan, Uri o char, dé formato a estos valores como cadenas (por ejemplo, llamando a ToString()) y llame a WriteStringValue.

Consulte también