Share via


JsonSerializerOptions-exemplaren instantiëren met System.Text.Json

In dit artikel wordt uitgelegd hoe u prestatieproblemen kunt voorkomen wanneer u gebruikt JsonSerializerOptions. Ook ziet u hoe u de parameters gebruikt die beschikbaar zijn.

JsonSerializerOptions-exemplaren opnieuw gebruiken

Als u herhaaldelijk met dezelfde opties gebruikt JsonSerializerOptions , maakt u niet telkens een nieuw JsonSerializerOptions exemplaar wanneer u deze gebruikt. Gebruik dezelfde instantie voor elke aanroep opnieuw. Deze richtlijnen zijn van toepassing op code die u schrijft voor aangepaste conversieprogramma's en wanneer u aanroept JsonSerializer.Serialize of JsonSerializer.Deserialize. Het is veilig om hetzelfde exemplaar te gebruiken voor meerdere threads. De metagegevenscaches op het optiesexemplaren zijn thread-safe en het exemplaar is onveranderbaar na de eerste serialisatie of deserialisatie.

In de volgende code ziet u de prestatiestraf voor het gebruik van nieuwe opties.

using System.Diagnostics;
using System.Text.Json;

namespace OptionsPerfDemo
{
    public record Forecast(DateTime Date, int TemperatureC, string Summary);

    public class Program
    {
        public static void Main()
        {
            Forecast forecast = new(DateTime.Now, 40, "Hot");
            JsonSerializerOptions options = new() { WriteIndented = true };
            int iterations = 100000;

            var watch = Stopwatch.StartNew();
            for (int i = 0; i < iterations; i++)
            {
                Serialize(forecast, options);
            }
            watch.Stop();
            Console.WriteLine($"Elapsed time using one options instance: {watch.ElapsedMilliseconds}");

            watch = Stopwatch.StartNew();
            for (int i = 0; i < iterations; i++)
            {
                Serialize(forecast);
            }
            watch.Stop();
            Console.WriteLine($"Elapsed time creating new options instances: {watch.ElapsedMilliseconds}");
        }

        private static void Serialize(Forecast forecast, JsonSerializerOptions? options = null)
        {
            _ = JsonSerializer.Serialize<Forecast>(
                forecast,
                options ?? new JsonSerializerOptions() { WriteIndented = true });
        }
    }
}

// Produces output like the following example:
//
//Elapsed time using one options instance: 190
//Elapsed time creating new options instances: 40140

Met de voorgaande code wordt een klein object 100.000 keer geserialiseerd met dezelfde instantie van opties. Vervolgens wordt hetzelfde object hetzelfde aantal keren geserialiseerd en wordt elke keer een nieuw exemplaar van opties gemaakt. Een typisch uitvoeringstijdverschil is 190 in vergelijking met 40.140 milliseconden. Het verschil is nog groter als u het aantal iteraties verhoogt.

De serializer ondergaat een opwarmfase tijdens de eerste serialisatie van elk type in de objectgrafiek wanneer er een nieuw exemplaar van opties aan wordt doorgegeven. Deze opwarmer omvat het maken van een cache met metagegevens die nodig zijn voor serialisatie. De metagegevens omvatten gemachtigden voor eigenschaps getters, setters, constructorargumenten, opgegeven kenmerken, enzovoort. Deze metagegevenscache wordt opgeslagen in het optiesexemplaren. Hetzelfde opwarmproces en dezelfde cache zijn van toepassing op deserialisatie.

De grootte van de metagegevenscache in een JsonSerializerOptions exemplaar is afhankelijk van het aantal typen dat moet worden geserialiseerd. Als u meerdere typen doorgeeft, bijvoorbeeld dynamisch gegenereerde typen, blijft de cachegrootte toenemen en kan dit een gevolg zijn van een OutOfMemoryException.

De JsonSerializerOptions.Default eigenschap

Als het exemplaar dat JsonSerializerOptions u moet gebruiken het standaardexemplaren is (met alle standaardinstellingen en de standaardconversieprogramma's), gebruikt u de JsonSerializerOptions.Default eigenschap in plaats van een exemplaar van opties te maken. Zie Standaardsysteemconversieprogramma gebruiken voor meer informatie.

JsonSerializerOptions kopiëren

Er is een JsonSerializerOptions-constructor waarmee u een nieuw exemplaar kunt maken met dezelfde opties als een bestaand exemplaar, zoals wordt weergegeven in het volgende voorbeeld:

using System.Text.Json;

namespace CopyOptions
{
    public class Forecast
    {
        public DateTime Date { get; init; }
        public int TemperatureC { get; set; }
        public string? Summary { get; set; }
    };

    public class Program
    {
        public static void Main()
        {
            Forecast forecast = new()
            {
                Date = DateTime.Now,
                TemperatureC = 40,
                Summary = "Hot"
            };

            JsonSerializerOptions options = new()
            {
                WriteIndented = true
            };

            JsonSerializerOptions optionsCopy = new(options);
            string forecastJson =
                JsonSerializer.Serialize<Forecast>(forecast, optionsCopy);

            Console.WriteLine($"Output JSON:\n{forecastJson}");
        }
    }
}

// Produces output like the following example:
//
//Output JSON:
//{
//  "Date": "2020-10-21T15:40:06.8998502-07:00",
//  "TemperatureC": 40,
//  "Summary": "Hot"
//}
Imports System.Text.Json
Imports System.Text.Json.Serialization

Namespace CopyOptions

    Public Class Forecast
        Public Property [Date] As Date
        Public Property TemperatureC As Integer
        Public Property Summary As String
    End Class

    Public NotInheritable Class Program

        Public Shared Sub Main()
            Dim forecast1 As New Forecast() With {
                .[Date] = Date.Now,
                .Summary = Nothing,
                .TemperatureC = CType(Nothing, Integer)
            }

            Dim options As New JsonSerializerOptions() With {
                .DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
            }

            Dim optionsCopy As New JsonSerializerOptions
            Dim forecastJson As String = JsonSerializer.Serialize(forecast1, optionsCopy)

            Console.WriteLine($"Output JSON:{forecastJson}")
        End Sub

    End Class

End Namespace

' Produces output like the following example:
'
'Output JSON:
'{
'  "Date": "2020-10-21T15:40:06.8998502-07:00",
'  "TemperatureC": 40,
'  "Summary": "Hot"
'}

De metagegevenscache van het bestaande JsonSerializerOptions exemplaar wordt niet gekopieerd naar het nieuwe exemplaar. Het gebruik van deze constructor is dus niet hetzelfde als het hergebruiken van een bestaand exemplaar van JsonSerializerOptions.

Webstandaarden voor JsonSerializerOptions

De volgende opties hebben verschillende standaardwaarden voor web-apps:

In .NET 9 en latere versies kunt u de JsonSerializerOptions.Web singleton gebruiken om te serialiseren met de standaardopties die ASP.NET Core gebruikt voor web-apps. Roep in eerdere versies de JsonSerializerOptions-constructor aan om een nieuw exemplaar te maken met de webstandaarden, zoals wordt weergegeven in het volgende voorbeeld:

using System.Text.Json;

namespace OptionsDefaults
{
    public class Forecast
    {
        public DateTime? Date { get; init; }
        public int TemperatureC { get; set; }
        public string? Summary { get; set; }
    };

    public class Program
    {
        public static void Main()
        {
            Forecast forecast = new()
            {
                Date = DateTime.Now,
                TemperatureC = 40,
                Summary = "Hot"
            };

            JsonSerializerOptions options = new(JsonSerializerDefaults.Web)
            {
                WriteIndented = true
            };

            Console.WriteLine(
                $"PropertyNameCaseInsensitive: {options.PropertyNameCaseInsensitive}");
            Console.WriteLine(
                $"JsonNamingPolicy: {options.PropertyNamingPolicy}");
            Console.WriteLine(
                $"NumberHandling: {options.NumberHandling}");

            string forecastJson = JsonSerializer.Serialize<Forecast>(forecast, options);
            Console.WriteLine($"Output JSON:\n{forecastJson}");

            Forecast? forecastDeserialized =
                JsonSerializer.Deserialize<Forecast>(forecastJson, options);

            Console.WriteLine($"Date: {forecastDeserialized?.Date}");
            Console.WriteLine($"TemperatureC: {forecastDeserialized?.TemperatureC}");
            Console.WriteLine($"Summary: {forecastDeserialized?.Summary}");
        }
    }
}

// Produces output like the following example:
//
//PropertyNameCaseInsensitive: True
//JsonNamingPolicy: System.Text.Json.JsonCamelCaseNamingPolicy
//NumberHandling: AllowReadingFromString
//Output JSON:
//{
//  "date": "2020-10-21T15:40:06.9040831-07:00",
//  "temperatureC": 40,
//  "summary": "Hot"
//}
//Date: 10 / 21 / 2020 3:40:06 PM
//TemperatureC: 40
//Summary: Hot
Imports System.Text.Json

Namespace OptionsDefaults

    Public Class Forecast
        Public Property [Date] As Date
        Public Property TemperatureC As Integer
        Public Property Summary As String
    End Class

    Public NotInheritable Class Program

        Public Shared Sub Main()
            Dim forecast1 As New Forecast() With {
                .[Date] = Date.Now,
                .TemperatureC = 40,
                .Summary = "Hot"
                }

            Dim options As New JsonSerializerOptions(JsonSerializerDefaults.Web) With {
                .WriteIndented = True
                }

            Console.WriteLine(
                $"PropertyNameCaseInsensitive: {options.PropertyNameCaseInsensitive}")
            Console.WriteLine(
                $"JsonNamingPolicy: {options.PropertyNamingPolicy}")
            Console.WriteLine(
                $"NumberHandling: {options.NumberHandling}")

            Dim forecastJson As String = JsonSerializer.Serialize(forecast1, options)
            Console.WriteLine($"Output JSON:{forecastJson}")

            Dim forecastDeserialized As Forecast = JsonSerializer.Deserialize(Of Forecast)(forecastJson, options)

            Console.WriteLine($"Date: {forecastDeserialized.[Date]}")
            Console.WriteLine($"TemperatureC: {forecastDeserialized.TemperatureC}")
            Console.WriteLine($"Summary: {forecastDeserialized.Summary}")
        End Sub

    End Class

End Namespace

' Produces output like the following example:
'
'PropertyNameCaseInsensitive: True
'JsonNamingPolicy: System.Text.Json.JsonCamelCaseNamingPolicy
'NumberHandling: AllowReadingFromString
'Output JSON:
'{
'  "date": "2020-10-21T15:40:06.9040831-07:00",
'  "temperatureC": 40,
'  "summary": "Hot"
'}
'Date: 10 / 21 / 2020 3:40:06 PM
'TemperatureC: 40
'Summary: Hot