Comment utiliser la génération de source dans System.Text.Json

La génération de source dans System.Text.Json est disponible dans .NET 6 et versions ultérieures. Lorsqu’elle est utilisée dans une application, la version de langage de l’application doit être C# 9.0 ou une version ultérieure. Cet article vous présente comment utiliser la sérialisation de génération source dans vos applications.

Pour obtenir plus d’informations sur les différents modes de génération de source, consultez les modes de génération de source.

Utiliser les valeurs par défaut de génération de source

Pour utiliser la génération de source avec tous les paramètres par défaut (les deux modes, options par défaut) :

  1. Créez une classe partielle qui dérive de JsonSerializerContext.

  2. Spécifiez le type à sérialiser ou désérialiser en appliquant JsonSerializableAttribute à la classe de contexte.

  3. Appelez une méthode JsonSerializer qui :

Par défaut, les deux modes de génération de source sont utilisés si vous n’en spécifiez pas. Pour plus d’informations sur la façon de spécifier le mode à utiliser, consultez la section Spécifier le mode de génération de source plus loin dans cet article.

Voici le type utilisé dans les exemples suivants :

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

Voici la classe de contexte configurée pour effectuer la génération de source pour la classe WeatherForecast précédente :

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

Les types de membres WeatherForecast n’ont pas besoin d’être spécifiés explicitement avec des attributs [JsonSerializable]. Les membres déclarés comme object sont une exception à cette règle. Le type d’exécution d’un membre déclaré comme object doit être spécifié. Par exemple, supposons que vous avez la classe suivante :

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

Et vous savez qu’au moment de l’exécution, elle peut avoir des objets boolean et int :

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

Ensuite, boolean et int doivent être déclarés comme [JsonSerializable] :

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

Pour spécifier la génération de source pour une collection, utilisez [JsonSerializable] avec le type de collection. Par exemple : [JsonSerializable(typeof(List<WeatherForecast>))].

Méthodes JsonSerializer qui utilisent la génération de source

Dans les exemples suivants, la propriété statique Default du type de contexte fournit une instance du type de contexte avec des options par défaut. L’instance de contexte fournit une propriété WeatherForecast qui retourne une instance JsonTypeInfo<WeatherForecast>. Vous pouvez spécifier un nom différent pour cette propriété à l’aide de la propriété TypeInfoPropertyName de l’attribut [JsonSerializable].

Exemple de sérialisation

Utilisation de JsonTypeInfo<T>:

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

Utilisation de JsonSerializerContext:

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

Utilisation de JsonSerializerOptions:

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

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

Exemples de désérialisation

Utilisation de JsonTypeInfo<T>:

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

Utilisation de JsonSerializerContext:

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

Utilisation de JsonSerializerOptions:

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

Exemple de programme complet

Voici les exemples précédents d’un programme complet :

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

Spécifier le mode de génération de source

Vous pouvez spécifier le mode basé sur les métadonnées ou le mode d’optimisation de la sérialisation pour un contexte entier qui peut inclure plusieurs types. Vous pouvez également spécifier le mode pour un type individuel. Si vous effectuez les deux, la spécification du mode pour un type gagne.

Exemple de mode d’optimisation de la sérialisation (chemin rapide)

  • Pour un contexte entier :

    [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SerializeOnlyContext : JsonSerializerContext
    {
    }
    
  • Pour un type individuel :

    [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)]
    internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext
    {
    }
    
  • Exemple de programme complet

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

Exemple de mode basé sur les métadonnées

  • Pour un contexte entier :

    [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);
    
  • Pour un type individuel :

    [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);
    
  • Exemple de programme complet

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

Prise en charge de la génération de source dans ASP.NET Core

Dans des applications Blazor, utilisez des surcharges de HttpClientJsonExtensions.GetFromJsonAsync et des méthodes d’extension HttpClientJsonExtensions.PostAsJsonAsync qui prennent un contexte de génération de source ou TypeInfo<TValue>.

À compter de .NET 8, vous pouvez également utiliser des surcharges de méthodes d’extension HttpClientJsonExtensions.GetFromJsonAsAsyncEnumerable qui acceptent un contexte de génération source ou TypeInfo<TValue>.

Dans Razor Pages, MVC, SignalR et les applications d’API web, utilisez la propriété JsonSerializerOptions.TypeInfoResolver pour spécifier le contexte.

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

Dans Razor Pages, MVC, SignalR et les applications d’API web, utilisez la propriété JsonSerializerOptions.TypeInfoResolver pour spécifier le contexte.

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

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

Dans Razor Pages, MVC, SignalR et les applications d’API web, utilisez la méthode AddContext de JsonSerializerOptions, comme illustré dans l’exemple suivant :

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

Remarque

JsonSourceGenerationMode.Serialization, ou sérialisation de chemin rapide, n’est pas prise en charge pour la sérialisation asynchrone.

Dans .NET 7 et les versions antérieures, cette limitation s’applique également aux surcharges synchrones de JsonSerializer.Serialize qui acceptent un Stream. À compter de .NET 8, même si la sérialisation de diffusion en continu nécessite des modèles basés sur des métadonnées, elle revient au chemin rapide si les charges utiles sont connues pour être suffisamment petites pour s’adapter à la taille prédéterminée de la mémoire tampon. Pour plus d’informations, consultez https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/#json.

Désactiver la valeur par défaut basée de la réflexion

Étant donné que System.Text.Json utilise la réflexion par défaut, l’appel d’une méthode de sérialisation de base peut interrompre les applications AOT natives qui ne prennent pas en charge toutes les API de réflexion requises. Ces interruptions peuvent être difficiles à diagnostiquer, car elles peuvent être imprévisibles et les applications sont souvent déboguées en utilisant le runtime CoreCLR où la réflexion fonctionne. Au lieu de cela, si vous désactivez explicitement la sérialisation basée sur la réflexion, les arrêts sont plus faciles à diagnostiquer. Le code qui utilise la sérialisation basée sur la réflexion entraîne la levée de InvalidOperationException avec un message descriptif au moment de l’exécution.

Pour désactiver la réflexion par défaut dans votre application, définissez la propriété MSBuild JsonSerializerIsReflectionEnabledByDefault sur false dans votre Fichier projet :

<PropertyGroup>
  <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
  • Le comportement de cette propriété est cohérent, quel que soit l’exécution, CoreCLR ou AOT natif.
  • Si vous ne spécifiez pas cette propriété et que PublishTrimmed est activé, la sérialisation basée sur la réflexion est automatiquement désactivée.

Vous pouvez vérifier par programmation si la réflexion est désactivée en utilisant la propriété JsonSerializer.IsReflectionEnabledByDefault. L’extrait de code suivant montre comment configurer votre sérialiseur selon que la réflexion est activée :

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

Étant donné que la propriété est traitée comme une constante au moment du lien, la méthode précédente ne roote pas le résolveur basé sur la réflexion dans les applications qui s’exécutent dans AOT natif.

Spécifier les options

Dans .NET 8 et versions ultérieures, la plupart des options que vous pouvez définir en tirant parti de JsonSerializerOptions peuvent également être définies en utilisant l’attribut JsonSourceGenerationOptionsAttribute. L’avantage de définir des options via l’attribut est que la configuration est spécifiée au moment de la compilation, ce qui garantit que la propriété MyContext.Default générée est préconfigurée avec toutes les options pertinentes définies.

Le code suivant montre comment définir des options à l’aide de l’attribut JsonSourceGenerationOptionsAttribute.

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

Lorsque vous utilisez JsonSourceGenerationOptionsAttribute pour spécifier des options de sérialisation, appelez l’une des méthodes de sérialisation suivantes :

  • Méthode JsonSerializer.Serialize qui prend un TypeInfo<TValue>. Transmettez-lui la propriété Default.<TypeName> de votre classe de contexte :

    jsonString = JsonSerializer.Serialize(
        weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);
    
  • Méthode JsonSerializer.Serialize qui prend un contexte. Transmettez-lui la propriété statique Default de votre classe de contexte.

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

Si vous appelez une méthode qui vous permet de transmettre votre propre instance de Utf8JsonWriter, le paramètre Indented de l’enregistreur est utilisé au lieu de l’option JsonSourceGenerationOptionsAttribute.WriteIndented.

Si vous créez et utilisez une instance de contexte en appelant le constructeur qui prend une instance JsonSerializerOptions, l’instance fournie est utilisée à la place des options spécifiées par JsonSourceGenerationOptionsAttribute.

Voici les exemples précédents d’un programme complet :

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

Spécifier des options à l’aide de JsonSerializerOptions

Certaines options de JsonSerializerOptions ne peuvent pas être définies en utilisant JsonSourceGenerationOptionsAttribute. Pour spécifier des options à l’aide de JsonSerializerOptions :

  • Créez une instance de JsonSerializerOptions.
  • Créez une instance de votre classe qui dérive de JsonSerializerContext, puis transmettez l’instance JsonSerializerOptions au constructeur.
  • Appelez les méthodes de sérialisation ou de désérialisation de JsonSerializer qui prennent une instance de contexte ou TypeInfo<TValue>.

Voici un exemple de classe de contexte suivi d’un exemple de code de sérialisation et de désérialisation :

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

Voici les exemples précédents d’un programme complet :

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

Combiner des générateurs de sources

Vous pouvez combiner des contrats à partir de plusieurs contextes générés par la source à l’intérieur d’une seule instance JsonSerializerOptions. Utilisez la propriété JsonSerializerOptions.TypeInfoResolver pour chaîner plusieurs contextes qui ont été combinés à l’aide de la méthode JsonTypeInfoResolver.Combine(IJsonTypeInfoResolver[]).

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

À compter de .NET 8, si vous souhaitez plus tard ajouter un autre contexte, vous pouvez le faire à l’aide de la propriété JsonSerializerOptions.TypeInfoResolverChain. L’ordre de la chaîne est significatif : JsonSerializerOptions interroge chacun des résolveurs dans leur ordre spécifié et retourne le premier résultat qui n’est pas 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.

Toute modification apportée à la propriété TypeInfoResolverChain est reflétée par TypeInfoResolver et inversement.

Sérialiser les champs d’énumération sous forme de chaînes

Par défaut, les énumérations sont sérialisées en tant que nombres. Pour sérialiser les champs d’une énumération spécifique sous forme de chaînes lors de l’utilisation de la génération source, annotez-la avec le convertisseur JsonStringEnumConverter<TEnum>. Ou pour définir une stratégie de couverture pour toutes les énumérations, utilisez l’attribut JsonSourceGenerationOptionsAttribute.

Convertisseur JsonStringEnumConverter<T>

Pour sérialiser des noms d’énumération sous forme de chaînes à l’aide de la génération source, utilisez le convertisseur JsonStringEnumConverter<TEnum>. (Le type non générique JsonStringEnumConverter n’est pas pris en charge par le runtime AOT natif.)

Annotez le type d’énumération avec le convertisseur JsonStringEnumConverter<TEnum> en tirant parti de l’attribut 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
}

Créez une classe JsonSerializerContext et annotez-la avec l’attribut JsonSerializableAttribute :

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

Le code suivant sérialise les noms d’énumération au lieu des valeurs numériques :

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

Le JSON obtenu ressemble à l’exemple suivant :

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

Stratégie de couverture

Au lieu d’utiliser le type JsonStringEnumConverter<TEnum>, vous pouvez appliquer une stratégie de couverture pour sérialiser des énumérations sous forme de chaînes à l’aide de JsonSourceGenerationOptionsAttribute. Créez une classe JsonSerializerContext et annotez-la avec les attributs JsonSerializableAttribute et JsonSourceGenerationOptionsAttribute :

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

Notez que l’énumération n’a pas 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
}

Voir aussi