Freigeben über


Verwenden der Quellgenerierung in System.Text.Json

Die Quellgenerierung in System.Text.Json ist in .NET 6 und höheren Versionen verfügbar. Bei Verwendung in einer App muss die Sprachversion der App C# 9.0 oder höher sein. In diesem Artikel erfahren Sie, wie Sie die Serialisierung der Quellgenerierung in Ihren Apps verwenden.

Informationen zu den verschiedenen Modi der Quellgenerierung finden Sie unter Quellengenerierungsmodi.

Verwenden der Quellgenerierungsstandards

So verwenden Sie die Quellgenerierung mit allen Standardwerten (beide Modi, Standardoptionen):

  1. Erstellen Sie eine von JsonSerializerContext abgeleitete partielle Klasse.

  2. Geben Sie den Typ an, der serialisiert oder deserialisiert werden soll, indem Sie JsonSerializableAttribute auf die Kontextklasse anwenden.

  3. Rufen Sie eine JsonSerializer-Methode auf, die entweder:

Standardmäßig werden beide Quellgenerierungsmodi verwendet, wenn Sie keinen angeben. Informationen zum Angeben des zu verwendenden Modus finden Sie weiter unten in diesem Artikel unter Angeben des Quellgenerierungsmodus.

Hier ist der Typ, der in den folgenden Beispielen verwendet wird:

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

Hier sehen Sie die Kontextklasse, die für die vorherige WeatherForecast-Klasse zur Quellgenerierung konfiguriert ist:

[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SourceGenerationContext : JsonSerializerContext
{
}

Die Typen von WeatherForecast-Membern müssen nicht explizit mit [JsonSerializable]-Attributen angegeben werden. Als object deklarierte Member sind eine Ausnahme von dieser Regel. Der Laufzeittyp für ein als object deklariertes Element muss angegeben werden. Angenommen, Sie verwenden folgende Klasse:

public class WeatherForecast
{
    public object? Data { get; set; }
    public List<object>? DataList { get; set; }
}

Und Sie wissen, dass es zur Laufzeit möglicherweise boolean- und int-Objekte gibt:

WeatherForecast wf = new() { Data = true, DataList = new List<object> { true, 1 } };

Dann müssen boolean und int als [JsonSerializable] deklariert werden:

[JsonSerializable(typeof(WeatherForecast))]
[JsonSerializable(typeof(bool))]
[JsonSerializable(typeof(int))]
public partial class WeatherForecastContext : JsonSerializerContext
{
}

Verwenden Sie zum Angeben der Quellgenerierung für eine Sammlung [JsonSerializable] mit dem Sammlungstyp. Beispiel: [JsonSerializable(typeof(List<WeatherForecast>))].

JsonSerializer-Methoden, die die Quellgenerierung verwenden

In den folgenden Beispielen stellt die statische Default-Eigenschaft des Kontexttyps eine Instanz des Kontexttyps mit Standardoptionen bereit. Die Kontextinstanz stellt eine WeatherForecast-Eigenschaft bereit, die eine JsonTypeInfo<WeatherForecast>-Instanz zurückgibt. Sie können einen anderen Namen für diese Eigenschaft angeben, indem Sie die TypeInfoPropertyName-Eigenschaft des [JsonSerializable]-Attributs verwenden.

Serialisierungsbeispiele

Verwenden von JsonTypeInfo<T>:

jsonString = JsonSerializer.Serialize(
    weatherForecast!, SourceGenerationContext.Default.WeatherForecast);

Verwenden von JsonSerializerContext:

jsonString = JsonSerializer.Serialize(
    weatherForecast, typeof(WeatherForecast), SourceGenerationContext.Default);

Verwenden von JsonSerializerOptions:

sourceGenOptions = new JsonSerializerOptions
{
    TypeInfoResolver = SourceGenerationContext.Default
};

jsonString = JsonSerializer.Serialize(
    weatherForecast, typeof(WeatherForecast), sourceGenOptions);

Deserialisierungsbeispiele

Verwenden von JsonTypeInfo<T>:

weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
    jsonString, SourceGenerationContext.Default.WeatherForecast);

Verwenden von JsonSerializerContext:

weatherForecast = JsonSerializer.Deserialize(
    jsonString, typeof(WeatherForecast), SourceGenerationContext.Default)
    as WeatherForecast;

Verwenden von JsonSerializerOptions:

var sourceGenOptions = new JsonSerializerOptions
{
    TypeInfoResolver = SourceGenerationContext.Default
};
weatherForecast = JsonSerializer.Deserialize(
    jsonString, typeof(WeatherForecast), sourceGenOptions)
    as WeatherForecast;

Vollständiges Programmbeispiel

Im Folgenden finden Sie die obigen Beispiele in einem vollständigen Programm:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace BothModesNoOptions
{
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }
    }

    [JsonSourceGenerationOptions(WriteIndented = true)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SourceGenerationContext : JsonSerializerContext
    {
    }

    public class Program
    {
        public static void Main()
        {
            string jsonString = """
                {
                    "Date": "2019-08-01T00:00:00",
                    "TemperatureCelsius": 25,
                    "Summary": "Hot"
                }
                """;
            WeatherForecast? weatherForecast;

            weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
                jsonString, SourceGenerationContext.Default.WeatherForecast);
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            weatherForecast = JsonSerializer.Deserialize(
                jsonString, typeof(WeatherForecast), SourceGenerationContext.Default)
                as WeatherForecast;
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            var sourceGenOptions = new JsonSerializerOptions
            {
                TypeInfoResolver = SourceGenerationContext.Default
            };
            weatherForecast = JsonSerializer.Deserialize(
                jsonString, typeof(WeatherForecast), sourceGenOptions)
                as WeatherForecast;
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            jsonString = JsonSerializer.Serialize(
                weatherForecast!, SourceGenerationContext.Default.WeatherForecast);
            Console.WriteLine(jsonString);
            // output:
            //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}

            jsonString = JsonSerializer.Serialize(
                weatherForecast, typeof(WeatherForecast), SourceGenerationContext.Default);
            Console.WriteLine(jsonString);
            // output:
            //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}

            sourceGenOptions = new JsonSerializerOptions
            {
                TypeInfoResolver = SourceGenerationContext.Default
            };

            jsonString = JsonSerializer.Serialize(
                weatherForecast, typeof(WeatherForecast), sourceGenOptions);
            Console.WriteLine(jsonString);
            // output:
            //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
        }
    }
}

Angeben des Quellgenerierungsmodus

Sie können den metadatenbasierten Modus oder den Serialisierungsoptimierungsmodus für einen gesamten Kontext angeben, der mehrere Typen umfassen kann. Alternativ können Sie den Modus für einen einzelnen Typ angeben. Wenn Sie beides tun, gewinnt die Modusspezifikation für einen Typ.

Beispiel für den Serialisierungsoptimierungsmodus (schneller Pfad)

  • Für einen gesamten Kontext:

    [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SerializeOnlyContext : JsonSerializerContext
    {
    }
    
  • Für einen einzelnen Typ:

    [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)]
    internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext
    {
    }
    
  • Vollständiges Programmbeispiel

    using System.Text.Json;
    using System.Text.Json.Serialization;
    
    namespace SerializeOnlyNoOptions
    {
        public class WeatherForecast
        {
            public DateTime Date { get; set; }
            public int TemperatureCelsius { get; set; }
            public string? Summary { get; set; }
        }
    
        [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
        [JsonSerializable(typeof(WeatherForecast))]
        internal partial class SerializeOnlyContext : JsonSerializerContext
        {
        }
        
        [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)]
        internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext
        {
        }
    
         public class Program
        {
            public static void Main()
            {
                string jsonString;
                WeatherForecast weatherForecast = new()
                    { Date = DateTime.Parse("2019-08-01"), TemperatureCelsius = 25, Summary = "Hot" };
    
                // Use context that selects Serialization mode only for WeatherForecast.
                jsonString = JsonSerializer.Serialize(weatherForecast,
                    SerializeOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
    
                // Use a context that selects Serialization mode.
                jsonString = JsonSerializer.Serialize(weatherForecast,
                    SerializeOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
            }
        }
    }
    

Beispiel für den metadatenbasierten Modus

  • Für einen gesamten Kontext:

    [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class MetadataOnlyContext : JsonSerializerContext
    {
    }
    
    jsonString = JsonSerializer.Serialize(
        weatherForecast!, MetadataOnlyContext.Default.WeatherForecast);
    
    weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
        jsonString, MetadataOnlyContext.Default.WeatherForecast);
    
  • Für einen einzelnen Typ:

    [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Metadata)]
    internal partial class MetadataOnlyWeatherForecastOnlyContext : JsonSerializerContext
    {
    }
    
    jsonString = JsonSerializer.Serialize(
        weatherForecast!,
        MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
    
    weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
        jsonString, MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
    
  • Vollständiges Programmbeispiel

    using System.Text.Json;
    using System.Text.Json.Serialization;
    
    namespace MetadataOnlyNoOptions
    {
        public class WeatherForecast
        {
            public DateTime Date { get; set; }
            public int TemperatureCelsius { get; set; }
            public string? Summary { get; set; }
        }
    
        [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Metadata)]
        internal partial class MetadataOnlyWeatherForecastOnlyContext : JsonSerializerContext
        {
        }
    
        [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
        [JsonSerializable(typeof(WeatherForecast))]
        internal partial class MetadataOnlyContext : JsonSerializerContext
        {
        }
    
        public class Program
        {
            public static void Main()
            {
                string jsonString = """
                    {
                      "Date": "2019-08-01T00:00:00",
                      "TemperatureCelsius": 25,
                      "Summary": "Hot"
                    }
                    """;
                WeatherForecast? weatherForecast;
    
                // Deserialize with context that selects metadata mode only for WeatherForecast only.
                weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
                    jsonString, MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
                Console.WriteLine($"Date={weatherForecast?.Date}");
                // output:
                //Date=8/1/2019 12:00:00 AM
    
                // Serialize with context that selects metadata mode only for WeatherForecast only.
                jsonString = JsonSerializer.Serialize(
                    weatherForecast!,
                    MetadataOnlyWeatherForecastOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
    
                // Deserialize with context that selects metadata mode only.
                weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
                    jsonString, MetadataOnlyContext.Default.WeatherForecast);
                Console.WriteLine($"Date={weatherForecast?.Date}");
                // output:
                //Date=8/1/2019 12:00:00 AM
    
                // Serialize with context that selects metadata mode only.
                jsonString = JsonSerializer.Serialize(
                    weatherForecast!, MetadataOnlyContext.Default.WeatherForecast);
                Console.WriteLine(jsonString);
                // output:
                //{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":"Hot"}
            }
        }
    }
    

Unterstützung der Quellgenerierung in ASP.NET Core

Verwenden Sie in Blazor-Apps Überladungen der Erweiterungsmethoden HttpClientJsonExtensions.GetFromJsonAsync und HttpClientJsonExtensions.PostAsJsonAsync, die einen Quellgenerierungskontext oder TypeInfo<TValue> verwenden.

Ab .NET 8 können Sie auch Überladungen von HttpClientJsonExtensions.GetFromJsonAsAsyncEnumerable Erweiterungsmethoden verwenden, die einen Quellgenerierungskontext akzeptierenTypeInfo<TValue>.

Verwenden Sie in Razor Pages, MVC-, SignalR- und Web-API-Apps die JsonSerializerOptions.TypeInfoResolver-Eigenschaft, um den Kontext anzugeben.

[JsonSerializable(typeof(WeatherForecast[]))]
internal partial class MyJsonContext : JsonSerializerContext { }
var serializerOptions = new JsonSerializerOptions
{
    TypeInfoResolver = MyJsonContext.Default
};

services.AddControllers().AddJsonOptions(
    static options =>
        options.JsonSerializerOptions.TypeInfoResolverChain.Add(MyJsonContext.Default));

Verwenden Sie in Razor Pages, MVC-, SignalR- und Web-API-Apps die JsonSerializerOptions.TypeInfoResolver-Eigenschaft, um den Kontext anzugeben.

[JsonSerializable(typeof(WeatherForecast[]))]
internal partial class MyJsonContext : JsonSerializerContext { }
var serializerOptions = new JsonSerializerOptions
{
    TypeInfoResolver = MyJsonContext.Default
};

services.AddControllers().AddJsonOptions(
    static options =>
        options.JsonSerializerOptions = serializerOptions);

Verwenden Sie in Razor Pages, MVC-, SignalR- und Web-API-Apps die AddContext-Methode von JsonSerializerOptions, wie im folgenden Beispiel gezeigt:

[JsonSerializable(typeof(WeatherForecast[]))]
internal partial class MyJsonContext : JsonSerializerContext { }
services.AddControllers().AddJsonOptions(options =>
    options.JsonSerializerOptions.AddContext<MyJsonContext>());

Hinweis

JsonSourceGenerationMode.Serialization oder die Serialisierung mit schnellem Pfad wird für die asynchrone Serialisierung nicht unterstützt.

In .NET 7 und früheren Versionen gilt diese Einschränkung auch für synchrone Überladungen von JsonSerializer.Serialize, die Stream akzeptieren. Obwohl die Streamingserialisierung metadatenbasierte Modelle erfordert, wird ab .NET 8 wieder auf den schnellen Pfad zurückgegriffen, wenn bekannt ist, dass die Nutzdaten klein genug für die vordefinierte Puffergröße sind. Weitere Informationen finden Sie unter https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/#json.

Reflexionsstandards deaktivieren

Da System.Text.Json die Reflexion standardmäßig verwendet, kann das Aufrufen einer einfachen Serialisierungsmethode native AOT-Apps unterbrechen, die nicht alle erforderlichen Reflexion-APIs unterstützen. Diese Unterbrechungen können schwierig zu diagnostizieren sein, da sie teils unvorhersehbar sind, und Apps werden häufig mithilfe der CoreCLR-Runtime gedebuggt, bei der die Reflexion funktioniert. Wenn Sie die reflexionsbasierte Serialisierung explizit deaktivieren, sind Unterbrechungen einfacher zu diagnostizieren. Code, der die reflexionsbasierte Serialisierung verwendet, führt dazu, dass zur Laufzeit eine InvalidOperationException mit beschreibender Meldung ausgelöst wird.

Um die Standardreflexion in Ihrer App zu deaktivieren, legen Sie die JsonSerializerIsReflectionEnabledByDefault MSBuild-Eigenschaft in der Projektdatei auf „false“ fest:

<PropertyGroup>
  <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
  • Das Verhalten dieser Eigenschaft ist unabhängig von der Runtime konsistent; entweder CoreCLR oder Native AOT.
  • Wenn Sie diese Eigenschaft nicht angeben und PublishTrimmed aktiviert ist, wird die reflexionsbasierte Serialisierung automatisch deaktiviert.

Mithilfe der JsonSerializer.IsReflectionEnabledByDefault-Eigenschaft können Sie programmgesteuert überprüfen, ob die Reflexion deaktiviert ist. Der folgende Codeausschnitt zeigt, wie Sie das Serialisierungsmodul konfigurieren können, je nachdem, ob die Reflexion aktiviert ist:

static JsonSerializerOptions CreateDefaultOptions()
{
    return new()
    {
        TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault
            ? new DefaultJsonTypeInfoResolver()
            : MyContext.Default
    };
}

Da die Eigenschaft als Verknüpfungszeitkonstante behandelt wird, basiert die vorherige Methode den reflexionsbasierten Resolver nicht in Anwendungen, die im nativen AOT ausgeführt werden.

Angeben von Optionen

In .NET 8 und höheren Versionen können die meisten Optionen, die Sie mit JsonSerializerOptions festlegen können, auch mithilfe des JsonSourceGenerationOptionsAttribute-Attributs festgelegt werden. Der Vorteil beim Festlegen von Optionen über das Attribut besteht darin, dass die Konfiguration zur Kompilierungszeit angegeben wird, wodurch sichergestellt wird, dass die generierte MyContext.Default-Eigenschaft mit allen relevanten Optionen vorkonfiguriert ist.

Der folgende Code zeigt, wie Optionen mithilfe des JsonSourceGenerationOptionsAttribute-Attributs festgelegt werden.

[JsonSourceGenerationOptions(
    WriteIndented = true,
    PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
    GenerationMode = JsonSourceGenerationMode.Serialization)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SerializationModeOptionsContext : JsonSerializerContext
{
}

Wenn Sie JsonSourceGenerationOptionsAttributeverwenden, um Serialisierungsoptionen anzugeben, rufen Sie eine der folgenden Serialisierungsmethoden auf:

  • Eine JsonSerializer.Serialize-Methode, die eine TypeInfo<TValue> akzeptiert. Übergeben Sie ihr die Default.<TypeName>-Eigenschaft Ihrer Kontextklasse:

    jsonString = JsonSerializer.Serialize(
        weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);
    
  • Eine JsonSerializer.Serialize-Methode, die einen Kontext akzeptiert. Übergeben Sie ihr die statische Default-Eigenschaft Ihrer Kontextklasse.

    jsonString = JsonSerializer.Serialize(
        weatherForecast, typeof(WeatherForecast), SerializationModeOptionsContext.Default);
    

Wenn Sie eine Methode aufrufen, mit der Sie Ihre eigene Instanz von Utf8JsonWriter übergeben können, wird die Indented-Einstellung des Writers anstelle der JsonSourceGenerationOptionsAttribute.WriteIndented-Option berücksichtigt.

Wenn Sie eine Kontextinstanz erstellen und verwenden, indem Sie den Konstruktor aufrufen, der eine JsonSerializerOptions-Instanz annimmt, wird die angegebene Instanz anstelle der von JsonSourceGenerationOptionsAttribute angegebenen Optionen verwendet.

Im Folgenden finden Sie die obigen Beispiele in einem vollständigen Programm:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace SerializeOnlyWithOptions
{
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }
    }

    [JsonSourceGenerationOptions(
        WriteIndented = true,
        PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
        GenerationMode = JsonSourceGenerationMode.Serialization)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SerializationModeOptionsContext : JsonSerializerContext
    {
    }
    public class Program
    {
        public static void Main()
        {
            string jsonString;
            WeatherForecast weatherForecast = new()
                { Date = DateTime.Parse("2019-08-01"), TemperatureCelsius = 25, Summary = "Hot" };

            // Serialize using TypeInfo<TValue> provided by the context
            // and options specified by [JsonSourceGenerationOptions].
            jsonString = JsonSerializer.Serialize(
                weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);
            Console.WriteLine(jsonString);
            // output:
            //{
            //  "date": "2019-08-01T00:00:00",
            //  "temperatureCelsius": 0,
            //  "summary": "Hot"
            //}

            // Serialize using Default context
            // and options specified by [JsonSourceGenerationOptions].
            jsonString = JsonSerializer.Serialize(
                weatherForecast, typeof(WeatherForecast), SerializationModeOptionsContext.Default);
            Console.WriteLine(jsonString);
            // output:
            //{
            //  "date": "2019-08-01T00:00:00",
            //  "temperatureCelsius": 0,
            //  "summary": "Hot"
            //}
        }
    }
}

Angeben von Optionen mit JsonSerializerOptions

Einige Optionen von JsonSerializerOptions können nicht mithilfe von JsonSourceGenerationOptionsAttribute festgelegt werden. So geben Sie Optionen mit JsonSerializerOptions an:

  • Erstellen Sie eine Instanz von JsonSerializerOptions:
  • Erstellen Sie eine Instanz Ihrer Klasse, die von JsonSerializerContextabgeleitet wird, und übergeben Sie die JsonSerializerOptions-Instanz an den Konstruktor.
  • Rufen Sie Serialisierungs- oder Deserialisierungsmethoden von JsonSerializer auf, die eine Kontextinstanz oder TypeInfo<TValue> verwenden.

Hier sehen Sie eine Beispielkontextklasse gefolgt von Beispielcode für Serialisierung und Deserialisierung:

[JsonSerializable(typeof(WeatherForecast))]
internal partial class OptionsExampleContext : JsonSerializerContext
{
}
jsonString = JsonSerializer.Serialize(
    weatherForecast,
    typeof(WeatherForecast),
    new OptionsExampleContext(
        JsonSerializerOptions.Web));
weatherForecast = JsonSerializer.Deserialize(
    jsonString,
    typeof(WeatherForecast),
    new OptionsExampleContext(
        JsonSerializerOptions.Web))
        as WeatherForecast;

Im Folgenden finden Sie die obigen Beispiele in einem vollständigen Programm:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace JsonSerializerOptionsExample
{
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }
    }

    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class OptionsExampleContext : JsonSerializerContext
    {
    }

    public class Program
    {
        public static void Main()
        {
            string jsonString = """
                {
                  "date": "2019-08-01T00:00:00",
                  "temperatureCelsius": 25,
                  "summary": "Hot"
                }
                """;
            WeatherForecast? weatherForecast;

            weatherForecast = JsonSerializer.Deserialize(
                jsonString,
                typeof(WeatherForecast),
                new OptionsExampleContext(
                    JsonSerializerOptions.Web))
                    as WeatherForecast;
            Console.WriteLine($"Date={weatherForecast?.Date}");
            // output:
            //Date=8/1/2019 12:00:00 AM

            jsonString = JsonSerializer.Serialize(
                weatherForecast,
                typeof(WeatherForecast),
                new OptionsExampleContext(
                    JsonSerializerOptions.Web));
            Console.WriteLine(jsonString);
            // output:
            //{ "date":"2019-08-01T00:00:00","temperatureCelsius":25,"summary":"Hot"}
        }
    }
}

Kombinieren von Quellgeneratoren

Sie können Verträge aus mehreren quellgenerierten Kontexten in einer einzelnen JsonSerializerOptions-Instanz kombinieren. Verwenden Sie die JsonSerializerOptions.TypeInfoResolver-Eigenschaft, um mehrere Kontexte zu verketten, die mithilfe der JsonTypeInfoResolver.Combine(IJsonTypeInfoResolver[])-Methode kombiniert wurden.

var options = new JsonSerializerOptions
{
    TypeInfoResolver = JsonTypeInfoResolver.Combine(ContextA.Default, ContextB.Default, ContextC.Default);
};

Ab .NET 8 können Sie später nach Bedarf mithilfe der JsonSerializerOptions.TypeInfoResolverChain-Eigenschaft einen anderen Kontext voranstellen oder anfügen. Die Reihenfolge der Kette ist wichtig: JsonSerializerOptions fragt die einzelnen Konfliktlöser in der angegebenen Reihenfolge ab und gibt das erste Ergebnis zurück, das ungleich NULL ist.

options.TypeInfoResolverChain.Add(ContextD.Default); // Append to the end of the list.
options.TypeInfoResolverChain.Insert(0, ContextE.Default); // Insert at the beginning of the list.

An der TypeInfoResolverChain-Eigenschaft vorgenommene Änderungen werden in TypeInfoResolver widergespiegelt und umgekehrt.

Serialisieren von Enumerationsfeldern als Zeichenfolgen

Standardmäßig werden Enumerationen als Zahlen serialisiert. Wenn Sie bei Verwendung der Quellgenerierung die Felder einer bestimmten Enumeration als Zeichenfolgen serialisieren möchten, kommentieren Sie sie mit dem JsonStringEnumConverter<TEnum>-Konverter. Verwenden Sie das JsonSourceGenerationOptionsAttribute-Attribut, um eine Rahmenrichtlinie für alle Enumerationen festzulegen.

JsonStringEnumConverter<T>-Konverter

Verwenden Sie den JsonStringEnumConverter<TEnum>-Konverter, um Enumerationsnamen als Zeichenfolgen mithilfe der Quellgenerierung zu serialisieren. (Der nicht generische JsonStringEnumConverter Typ wird von der nativen AOT-Laufzeit nicht unterstützt.)

Kommentieren Sie den Enumerationstyp mit dem JsonStringEnumConverter<TEnum>-Konverter mithilfe des JsonConverterAttribute-Attributs:

public class WeatherForecastWithPrecipEnum
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public Precipitation? Precipitation { get; set; }
}

[JsonConverter(typeof(JsonStringEnumConverter<Precipitation>))]
public enum Precipitation
{
    Drizzle, Rain, Sleet, Hail, Snow
}

Erstellen Sie eine JsonSerializerContext Klasse, und kommentieren Sie sie mit dem JsonSerializableAttribute Attribut:

[JsonSerializable(typeof(WeatherForecastWithPrecipEnum))]
public partial class Context1 : JsonSerializerContext { }

Im folgenden Code werden die Enumerationsnamen anstelle der numerischen Werte serialisiert:

var weatherForecast = new WeatherForecastWithPrecipEnum
{
    Date = DateTime.Parse("2019-08-01"),
    TemperatureCelsius = 25,
    Precipitation = Precipitation.Sleet
};

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    TypeInfoResolver = Context1.Default,
};
string? jsonString = JsonSerializer.Serialize(weatherForecast, options);

Das resultierende JSON sieht wie im folgenden Beispiel aus:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Precipitation": "Sleet"
}

Rahmenrichtlinie

Anstatt den JsonStringEnumConverter<TEnum>-Typ zu verwenden, können Sie eine Rahmenrichtlinie anwenden, um Enumerationen als Zeichenfolgen mithilfe der JsonSourceGenerationOptionsAttribute. Erstellen Sie eine JsonSerializerContext-Klasse, und kommentieren Sie sie mit den folgenden JsonSerializableAttribute- und JsonSourceGenerationOptionsAttribute-Attributen:

[JsonSourceGenerationOptions(UseStringEnumConverter = true)]
[JsonSerializable(typeof(WeatherForecast2WithPrecipEnum))]
public partial class Context2 : JsonSerializerContext { }

Beachten Sie, dass die Enumeration nicht über JsonConverterAttributeverfügt:

public class WeatherForecast2WithPrecipEnum
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public Precipitation2? Precipitation { get; set; }
}

public enum Precipitation2
{
    Drizzle, Rain, Sleet, Hail, Snow
}

Benutzerdefinierte Enumerationsmemembnamen

Ab .NET 9 können Sie Enumerationsmember-Namen mithilfe des JsonStringEnumMemberName-Attributs anpassen. Weitere Informationen finden Sie unter Benutzerdefinierten Enumerationsmember-Namen.

Siehe auch