Come usare Utf8JsonWriter in System.Text.Json

Questo articolo illustra come usare il tipo di Utf8JsonWriter per la creazione di serializzatori personalizzati.

Utf8JsonWriter è un modo ad alte prestazioni per scrivere testo JSON con codifica UTF-8 da tipi .NET comuni come String, Int32e DateTime. Il writer è un tipo di basso livello che può essere usato per creare serializzatori personalizzati. Il metodo JsonSerializer.Serialize usa Utf8JsonWriter dietro le quinte.

Nell'esempio seguente viene illustrato come utilizzare la classe 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)

Scrivere con testo UTF-8

Per ottenere prestazioni ottimali durante l'uso di Utf8JsonWriter, scrivere i payload JSON già codificati come testo UTF-8 anziché come stringhe UTF-16. Usare JsonEncodedText per memorizzare nella cache e precodificare i nomi e i valori delle proprietà di stringa noti come statici e passarli al writer anziché usare valori letterali stringa UTF-16. Questa operazione è più veloce rispetto alla memorizzazione nella cache e all'uso di matrici di byte UTF-8.

Questo approccio funziona anche se è necessario eseguire l'escape personalizzato. System.Text.Json non consente di disabilitare l'escape durante la scrittura di una stringa. Tuttavia, è possibile passare il proprio JavaScriptEncoder personalizzato come opzione al writer o creare un JsonEncodedText personalizzato che usa il JavascriptEncoder per eseguire l'escape e quindi scrivere il JsonEncodedText anziché la stringa. Per altre informazioni, vedere Personalizzare la codifica dei caratteri.

Scrivere JSON non elaborato

In alcuni scenari, potrebbe essere necessario scrivere JSON "non elaborato" in un payload JSON che si sta creando con Utf8JsonWriter. A tale scopo, è possibile usare Utf8JsonWriter.WriteRawValue. Ecco alcuni scenari tipici:

  • Si dispone di un payload JSON esistente che si vuole racchiudere in un nuovo JSON.

  • Si desidera formattare i valori in modo diverso rispetto alla formattazione predefinita Utf8JsonWriter.

    Ad esempio, è possibile personalizzare la formattazione dei numeri. Per impostazione predefinita, System.Text.Json omette il separatore decimale per i numeri interi, scrivendo 1 anziché 1.0, ad esempio. La logica è che la scrittura con meno byte garantisce prestazioni migliori. Si supponga tuttavia che il consumer del codice JSON consideri i numeri con decimali come doppi e i numeri senza decimali come numeri interi. È possibile assicurarsi che i numeri in una matrice siano tutti riconosciuti come doppi, scrivendo un separatore decimale e zero per i numeri interi. L'esempio seguente illustra come eseguire questa operazione:

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

Personalizzare l'escape dei caratteri

L'impostazione StringEscapeHandling di JsonTextWriter offre opzioni di escape per tutti i caratteri non ASCII o caratteri HTML. Per impostazione predefinita, Utf8JsonWriter esegue l'escape di tutti i caratteri HTML non ASCII e. Questo escape viene eseguito per motivi di sicurezza approfonditi. Per specificare un criterio di escape diverso, creare un JavaScriptEncoder e impostare JsonWriterOptions.Encoder. Per altre informazioni, vedere Personalizzare la codifica dei caratteri.

Scrivere valori Null

Per scrivere valori Null usando Utf8JsonWriter, chiamare:

  • WriteNull per scrivere una coppia chiave-valore con null come valore.
  • WriteNullValue per scrivere null come elemento di una matrice JSON.

Per una proprietà stringa, se la stringa è null, WriteString e WriteStringValue sono equivalenti a WriteNull e WriteNullValue.

Scrivere valori Timespan, Uri o char

Per scrivere valori Timespan, Urio char, formattarli come stringhe (chiamando ad esempio ToString()) e chiamare WriteStringValue.

Vedi anche