Jak używać generowania źródła w programie System.Text.Json

Generowanie źródła w programie System.Text.Json jest dostępne na platformie .NET 6 i nowszych wersjach. W przypadku użycia w aplikacji wersja językowa aplikacji musi być C# 9.0 lub nowsza. W tym artykule pokazano, jak używać serializacji opartej na generowaniu źródła w aplikacjach.

Aby uzyskać informacje na temat różnych trybów generowania źródła, zobacz Tryby generowania źródła.

Używanie wartości domyślnych generowania źródła

Aby użyć generowania źródła ze wszystkimi ustawieniami domyślnymi (oba tryby, opcje domyślne):

  1. Utwórz klasę częściową, która pochodzi z klasy JsonSerializerContext.

  2. Określ typ do serializacji lub deserializacji, stosując JsonSerializableAttribute do klasy kontekstu.

  3. Wywołaj metodę JsonSerializer , która:

Domyślnie oba tryby generowania źródła są używane, jeśli go nie określisz. Aby uzyskać informacje na temat sposobu określania trybu do użycia, zobacz Określanie trybu generowania źródła w dalszej części tego artykułu.

Oto typ, który jest używany w następujących przykładach:

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

Oto klasa kontekstu skonfigurowana do generowania źródła dla poprzedniej WeatherForecast klasy:

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

Typy elementów WeatherForecast członkowskich nie muszą być jawnie określone za pomocą [JsonSerializable] atrybutów. Członkowie zadeklarowani jako object są wyjątkiem od tej reguły. Należy określić typ środowiska uruchomieniowego dla elementu członkowskiego zadeklarowanego zgodnie object z potrzebami. Załóżmy na przykład, że masz następującą klasę:

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

Wiesz też, że w czasie wykonywania może on mieć boolean obiekty i int :

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

Następnie boolean należy int zadeklarować jako [JsonSerializable]:

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

Aby określić generowanie źródła dla kolekcji, użyj wartości [JsonSerializable] z typem kolekcji. Na przykład: [JsonSerializable(typeof(List<WeatherForecast>))].

JsonSerializer metody korzystające z generowania źródła

W poniższych przykładach właściwość statyczna Default typu kontekstu udostępnia wystąpienie typu kontekstu z opcjami domyślnymi. Wystąpienie kontekstu udostępnia właściwość zwracającą WeatherForecastJsonTypeInfo<WeatherForecast> wystąpienie. Dla tej właściwości można określić inną nazwę, używając TypeInfoPropertyName właściwości atrybutu [JsonSerializable] .

Przykłady serializacji

Za pomocą polecenia JsonTypeInfo<T>:

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

Za pomocą polecenia JsonSerializerContext:

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

Za pomocą polecenia JsonSerializerOptions:

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

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

Przykłady deserializacji

Za pomocą polecenia JsonTypeInfo<T>:

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

Za pomocą polecenia JsonSerializerContext:

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

Za pomocą polecenia JsonSerializerOptions:

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

Kompletny przykład programu

Poniżej przedstawiono powyższe przykłady w kompletnym programie:

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"}
        }
    }
}

Określanie trybu generowania źródła

Można określić tryb oparty na metadanych lub tryb optymalizacji serializacji dla całego kontekstu, który może zawierać wiele typów. Możesz też określić tryb dla pojedynczego typu. Jeśli to zrobisz, specyfikacja trybu dla typu wygrywa.

Przykładowy tryb optymalizacji serializacji (szybka ścieżka)

  • Dla całego kontekstu:

    [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SerializeOnlyContext : JsonSerializerContext
    {
    }
    
  • Dla pojedynczego typu:

    [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)]
    internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext
    {
    }
    
  • Kompletny przykład programu

    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"}
            }
        }
    }
    

Przykład trybu opartego na metadanych

  • Dla całego kontekstu:

    [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);
    
  • Dla pojedynczego typu:

    [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);
    
  • Kompletny przykład programu

    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":0,"Summary":"Hot"}
            }
        }
    }
    

Obsługa generowania źródła w programie ASP.NET Core

W aplikacjach platformy Blazor użyj przeciążeń metod rozszerzeń HttpClientJsonExtensions.GetFromJsonAsync i HttpClientJsonExtensions.PostAsJsonAsync , które przyjmują kontekst generowania źródła lub TypeInfo<TValue>.

Począwszy od platformy .NET 8, można również użyć przeciążeń metod rozszerzeń HttpClientJsonExtensions.GetFromJsonAsAsyncEnumerable , które akceptują kontekst generowania źródła lub TypeInfo<TValue>.

W aplikacjach Razor Pages, MVC, SignalR i Web API użyj JsonSerializerOptions.TypeInfoResolver właściwości , aby określić kontekst.

[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));

W aplikacjach Razor Pages, MVC, SignalR i Web API użyj JsonSerializerOptions.TypeInfoResolver właściwości , aby określić kontekst.

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

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

W aplikacjach Razor Pages, MVC, SignalR i Web API użyj AddContext metody JsonSerializerOptions, jak pokazano w poniższym przykładzie:

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

Uwaga

JsonSourceGenerationMode.Serializationserializacja typu lub szybka ścieżka nie jest obsługiwana w przypadku serializacji asynchronicznej.

W programie .NET 7 i starszych wersjach to ograniczenie dotyczy również synchronicznych przeciążeń JsonSerializer.Serialize , które akceptują Streamelement . Począwszy od platformy .NET 8, mimo że serializacja strumieniowa wymaga modeli opartych na metadanych, wróci do szybkiej ścieżki, jeśli ładunki są znane jako wystarczająco małe, aby zmieścić się w wstępnie określonym rozmiarze buforu. Aby uzyskać więcej informacji, zobacz https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/#json.

Wyłącz wartości domyślne odbicia

Ponieważ System.Text.Json domyślnie używa odbicia, wywołanie podstawowej metody serializacji może przerwać natywne aplikacje AOT, które nie obsługują wszystkich wymaganych interfejsów API odbicia. Te przerwy mogą być trudne do zdiagnozowania, ponieważ mogą być nieprzewidywalne, a aplikacje są często debugowane przy użyciu środowiska uruchomieniowego CoreCLR, w którym działa odbicie. Zamiast tego, jeśli jawnie wyłączysz serializacji opartej na odbiciu, przerwy są łatwiejsze do zdiagnozowania. Kod korzystający z serializacji opartej na odbiciu spowoduje InvalidOperationException zgłoszenie komunikatu opisowego w czasie wykonywania.

Aby wyłączyć domyślne odbicie w aplikacji, ustaw JsonSerializerIsReflectionEnabledByDefault właściwość MSBuild na false w pliku projektu:

<PropertyGroup>
  <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
  • Zachowanie tej właściwości jest spójne niezależnie od środowiska uruchomieniowego, CoreCLR lub Native AOT.
  • Jeśli nie określisz tej właściwości i opcja PublishTrimmed jest włączona, serializacja oparta na odbiciu zostanie automatycznie wyłączona.

Można programowo sprawdzić, czy odbicie jest wyłączone przy użyciu JsonSerializer.IsReflectionEnabledByDefault właściwości . Poniższy fragment kodu pokazuje, jak można skonfigurować serializator w zależności od tego, czy odbicie jest włączone:

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

Ponieważ właściwość jest traktowana jako stała czasu połączenia, poprzednia metoda nie korzeń modułu rozpoznawania opartego na odbiciu w aplikacjach uruchamianych w natywnej AOT.

Określanie opcji

W programie .NET 8 i nowszych wersjach większość opcji, które można ustawić przy użyciu JsonSerializerOptions , można również ustawić przy użyciu atrybutu JsonSourceGenerationOptionsAttribute . Zaletą ustawienia opcji za pośrednictwem atrybutu jest to, że konfiguracja jest określona w czasie kompilacji, co gwarantuje, że wygenerowana MyContext.Default właściwość jest wstępnie skonfigurowana ze wszystkimi odpowiednimi zestawami opcji.

Poniższy kod pokazuje, jak ustawić opcje przy użyciu atrybutu JsonSourceGenerationOptionsAttribute .

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

W przypadku określania JsonSourceGenerationOptionsAttribute opcji serializacji wywołaj jedną z następujących metod serializacji:

  • Metoda JsonSerializer.Serialize , która przyjmuje metodę TypeInfo<TValue>. Przekaż jej Default.<TypeName> właściwość klasy kontekstu:

    jsonString = JsonSerializer.Serialize(
        weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);
    
  • JsonSerializer.Serialize Metoda, która przyjmuje kontekst. Przekaż jej właściwość statyczną Default klasy kontekstu.

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

Jeśli wywołasz metodę, która umożliwia przekazanie własnego wystąpienia Utf8JsonWriterobiektu , ustawienie składnika zapisywania Indented zostanie uznane zamiast JsonSourceGenerationOptionsAttribute.WriteIndented opcji.

Jeśli utworzysz wystąpienie kontekstu i użyjesz go przez wywołanie konstruktora, który przyjmuje JsonSerializerOptions wystąpienie, podane wystąpienie zostanie użyte zamiast opcji określonych przez JsonSourceGenerationOptionsAttribute.

Poniżej przedstawiono powyższe przykłady w kompletnym programie:

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

Określanie opcji przy użyciu polecenia JsonSerializerOptions

Niektórych opcji JsonSerializerOptions nie można ustawić przy użyciu polecenia JsonSourceGenerationOptionsAttribute. Aby określić opcje przy użyciu polecenia JsonSerializerOptions:

  • Utwórz wystąpienie elementu JsonSerializerOptions.
  • Utwórz wystąpienie klasy, które pochodzi z JsonSerializerContextklasy , i przekaż JsonSerializerOptions wystąpienie do konstruktora.
  • Wywołaj metody JsonSerializer serializacji lub deserializacji, które przyjmują wystąpienie kontekstu lub TypeInfo<TValue>.

Oto przykładowa klasa kontekstu, po której następuje przykładowy kod serializacji i deserializacji:

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

Poniżej przedstawiono powyższe przykłady w kompletnym programie:

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(
                    new JsonSerializerOptions(JsonSerializerDefaults.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(
                    new JsonSerializerOptions(JsonSerializerDefaults.Web)));
            Console.WriteLine(jsonString);
            // output:
            //{ "date":"2019-08-01T00:00:00","temperatureCelsius":25,"summary":"Hot"}
        }
    }
}

Łączenie generatorów źródłowych

Kontrakty można łączyć z wielu kontekstów generowanych przez źródło w jednym JsonSerializerOptions wystąpieniu. JsonSerializerOptions.TypeInfoResolver Użyj właściwości , aby połączyć wiele kontekstów przy użyciu JsonTypeInfoResolver.Combine(IJsonTypeInfoResolver[]) metody .

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

Począwszy od platformy .NET 8, jeśli później chcesz wstępnie utworzyć lub dołączyć inny kontekst, możesz to zrobić przy użyciu JsonSerializerOptions.TypeInfoResolverChain właściwości . Kolejność łańcucha jest znacząca: JsonSerializerOptions wykonuje zapytania względem każdego z modułów rozpoznawania w określonej kolejności i zwraca pierwszy wynik, który nie ma wartości null.

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.

Wszelkie zmiany wprowadzone w TypeInfoResolverChain właściwości są odzwierciedlane przez TypeInfoResolver i na odwrót.

Serializowanie pól wyliczenia jako ciągów

Domyślnie wyliczenia są serializowane jako liczby. Aby serializować pola określonego wyliczenia jako ciągi podczas używania generowania źródła, dodaj do niego adnotację z konwerterem JsonStringEnumConverter<TEnum> . Możesz też ustawić zasady ogólne dla wszystkich wyliczenia, użyj atrybutu JsonSourceGenerationOptionsAttribute .

JsonStringEnumConverter<T> Konwerter

Aby serializować nazwy wyliczenia jako ciągi przy użyciu generowania źródła, użyj konwertera JsonStringEnumConverter<TEnum> . (Typ niegeneryczny JsonStringEnumConverter nie jest obsługiwany przez natywne środowisko uruchomieniowe AOT).

Dodaj adnotację do typu wyliczenia z konwerterem JsonStringEnumConverter<TEnum> przy użyciu atrybutu JsonConverterAttribute :

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
}

Utwórz klasę JsonSerializerContext i dodaj do niej adnotację za pomocą atrybutu JsonSerializableAttribute :

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

Poniższy kod serializuje nazwy wyliczenia zamiast wartości liczbowych:

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);

Wynikowy kod JSON wygląda następująco:

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

Zasady ogólne

Zamiast używać JsonStringEnumConverter<TEnum> typu, można zastosować zasady ogólne do serializacji wyliczenia jako ciągów przy użyciu .JsonSourceGenerationOptionsAttribute Utwórz klasę JsonSerializerContext i dodaj do niej adnotację za JsonSerializableAttributepomocą atrybutów i JsonSourceGenerationOptionsAttribute :

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

Zwróć uwagę, że wyliczenie nie ma wartości JsonConverterAttribute:

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
}

Zobacz też