Compartilhar via


Como usar a geração de origem em System.Text.Json

A geração de fonte no System.Text.Json está disponível no .NET 6 e em versões posteriores. Quando usado em um aplicativo, a versão do idioma do aplicativo deve ser C# 9.0 ou posterior. Este artigo mostra como usar a serialização baseada na geração de origem em seus aplicativos.

Para obter informações sobre os diferentes modos de geração de origem, confira os Modos de geração de origem.

Usar padrões de geração de origem

Para usar a geração de origem com todos os padrões (ambos os modos, opções padrão):

  1. Crie uma classe parcial que deriva de JsonSerializerContext.

  2. Especifique o tipo para serializar ou desserializar aplicando JsonSerializableAttribute à classe de contexto.

  3. Chame um método JsonSerializer que:

Por padrão, ambos os modos de geração de origem são usados se você não especificar um. Para obter informações sobre como especificar o modo a ser usado, consulte Especificar modo de geração de origem posteriormente neste artigo.

Aqui está o tipo que é usado nos exemplos a seguir:

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

Aqui está a classe de contexto configurada para gerar a fonte para a classe WeatherForecast anterior:

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

Os tipos de membros WeatherForecast não precisam ser especificados explicitamente com atributos [JsonSerializable]. Membros declarados como object são uma exceção a esta regra. O tipo de runtime para um membro declarado como object precisa ser especificado. Por exemplo, suponha que você tenha a seguinte classe:

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

E você sabe que em runtime pode ter objetos boolean e int:

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

Então boolean e int devem ser declarados como [JsonSerializable]:

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

Para especificar a geração de origem para uma coleção, use [JsonSerializable] com o tipo de coleção. Por exemplo: [JsonSerializable(typeof(List<WeatherForecast>))].

JsonSerializer métodos que usam geração de origem

Nos exemplos a seguir, a propriedade estática Default do tipo de contexto fornece uma instância do tipo de contexto com opções padrão. A instância de contexto fornece uma propriedade WeatherForecast que retorna uma instância JsonTypeInfo<WeatherForecast>. Você pode especificar um nome diferente para esta propriedade usando a propriedade TypeInfoPropertyName do atributo [JsonSerializable].

Exemplos de serialização

Usando JsonTypeInfo<T>:

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

Usando JsonSerializerContext:

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

Usando JsonSerializerOptions:

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

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

Exemplos de desserialização

Usando JsonTypeInfo<T>:

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

Usando JsonSerializerContext:

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

Usando JsonSerializerOptions:

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

Exemplo de programa completo

Aqui estão os exemplos anteriores em um programa completo:

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

Especifique o modo de geração de origem

Você pode especificar o modo baseado em metadados ou o modo de otimização de serialização para um contexto inteiro, que pode incluir vários tipos. Ou você pode especificar o modo para um tipo individual. Se você fizer as duas coisas, a especificação de modo para um tipo prevalece.

Exemplo do modo serialização-otimização (caminho rápido)

  • Para um contexto inteiro:

    [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
    [JsonSerializable(typeof(WeatherForecast))]
    internal partial class SerializeOnlyContext : JsonSerializerContext
    {
    }
    
  • Para um tipo individual:

    [JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)]
    internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext
    {
    }
    
  • Exemplo de programa completo

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

Exemplo do modo baseado em metadados

  • Para um contexto inteiro:

    [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);
    
  • Para um tipo individual:

    [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);
    
  • Exemplo de programa completo

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

Suporte à geração de origem no ASP.NET Core

Em aplicativos Blazor, use sobrecargas e métodos de extensão HttpClientJsonExtensions.GetFromJsonAsync e HttpClientJsonExtensions.PostAsJsonAsync que usam um contexto de geração de origem ou TypeInfo<TValue>.

A partir do .NET 8, você também pode usar sobrecargas de métodos de extensão HttpClientJsonExtensions.GetFromJsonAsAsyncEnumerable que aceitam um contexto de geração de origem ou TypeInfo<TValue>.

Em aplicativos do Razor Pages, MVC, SignalR e de API Web, use a propriedade JsonSerializerOptions.TypeInfoResolver para especificar o contexto.

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

Em aplicativos do Razor Pages, MVC, SignalR e de API Web, use a propriedade JsonSerializerOptions.TypeInfoResolver para especificar o contexto.

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

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

Em aplicativos do Razor Pages, MVC, SignalR e de API Web, use o método AddContext de JsonSerializerOptions, conforme mostrado no exemplo a seguir:

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

Observação

JsonSourceGenerationMode.Serialization ou serialização de caminho rápido, não tem suporte para serialização assíncrona.

No .NET 7 e versões anteriores, essa limitação também se aplica a sobrecargas síncronas de JsonSerializer.Serialize que aceitam um arquivo Stream. A partir do .NET 8, mesmo que a serialização de streaming exija modelos baseados em metadados, ela voltará ao caminho rápido se os conteúdos forem conhecidos por serem pequenos o suficiente para se ajustarem ao tamanho do buffer predeterminado. Para obter mais informações, consulte https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/#json.

Desabilitar padrões de reflexão

Como o System.Text.Json usa reflexão por padrão, chamar um método básico de serialização pode interromper aplicativos Native AOT, que não dão suporte a todas as APIs de reflexão necessárias. Essas interrupções podem ser desafiadoras para diagnosticar, pois podem ser imprevisíveis, e os aplicativos muitas vezes são depurados usando o runtime CoreCLR, onde a reflexão funciona. Em vez disso, se você desabilitar explicitamente a serialização baseada em reflexão, as interrupções serão mais fáceis de diagnosticar. O código que usa serialização baseada em reflexão fará com que uma InvalidOperationException com uma mensagem descritiva seja gerada durante o tempo de execução.

Para desabilitar a reflexão padrão em seu aplicativo, defina a propriedade MSBuild JsonSerializerIsReflectionEnabledByDefault como false em seu arquivo de projeto:

<PropertyGroup>
  <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
  • O comportamento dessa propriedade é consistente independentemente do runtime, seja CoreCLR ou Native AOT.
  • Se você não especificar essa propriedade e PublishTrimmed estiver habilitado, a serialização baseada em reflexão será desabilitada automaticamente.

Você pode verificar programaticamente se a reflexão está desabilitada usando a propriedade JsonSerializer.IsReflectionEnabledByDefault. O snippet de código a seguir mostra como você pode configurar seu serializador dependendo se a reflexão está habilitada:

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

Como a propriedade é tratada como uma constante de tempo de link, o método anterior não enraíza o resolvedor baseado em reflexão em aplicativos executados no Native AOT.

Especificar opções

No .NET 8 e versões posteriores, a maioria das opções que você pode definir usando JsonSerializerOptions também pode ser definida usando o atributo JsonSourceGenerationOptionsAttribute. A vantagem de definir opções por meio do atributo é que a configuração é especificada em tempo de compilação, garantindo que a propriedade MyContext.Default gerada seja pré-configurada com todas as opções relevantes definidas.

O código a seguir mostra como definir opções usando o atributo JsonSourceGenerationOptionsAttribute.

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

Ao usar JsonSourceGenerationOptionsAttribute para especificar opções de serialização, chame um dos seguintes métodos de serialização:

  • Um método JsonSerializer.Serialize que usa um TypeInfo<TValue>. Passe a propriedade Default.<TypeName> da classe de contexto:

    jsonString = JsonSerializer.Serialize(
        weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);
    
  • Um método JsonSerializer.Serialize que usa um contexto. Passe a propriedade estática Default de sua classe de contexto.

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

Se você chamar um método que permite passar em sua própria instância de Utf8JsonWriter, a configuração Indented do gravador é respeitada em vez da opção JsonSourceGenerationOptionsAttribute.WriteIndented.

Se você criar e usar uma instância de contexto chamando o construtor que usa uma instância JsonSerializerOptions, a instância fornecida será usada em vez das opções especificadas por JsonSourceGenerationOptionsAttribute.

Aqui estão os exemplos anteriores em um programa completo:

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

Especificar opções usando JsonSerializerOptions

Algumas opções de JsonSerializerOptions não podem ser definidas usando JsonSourceGenerationOptionsAttribute. Para especificar opções usando JsonSerializerOptions:

  • Crie uma instância de JsonSerializerOptions.
  • Crie uma instância de sua classe que deriva de JsonSerializerContext e passe a instância JsonSerializerOptions para o construtor.
  • Chame métodos de serialização ou desserialização de JsonSerializer que usam uma instância de contexto ou TypeInfo<TValue>.

Aqui está uma classe de contexto de exemplo seguida pelo código de exemplo de serialização e desserialização:

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

Aqui estão os exemplos anteriores em um programa completo:

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

Combinar geradores de origem

Você pode combinar contratos de vários contextos gerados pela origem dentro de uma única instância de JsonSerializerOptions. Use a propriedade JsonSerializerOptions.TypeInfoResolver para encadear vários contextos que foram combinados usando o método JsonTypeInfoResolver.Combine(IJsonTypeInfoResolver[]).

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

A partir do .NET 8, se você quiser preceder ou acrescentar outro contexto posteriormente, poderá fazê-lo usando a propriedade JsonSerializerOptions.TypeInfoResolverChain. A ordenação da cadeia é significativa: JsonSerializerOptions consulta cada um dos resolvedores em sua ordem especificada e retorna o primeiro resultado que não é nulo.

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.

Qualquer alteração feita na propriedade TypeInfoResolverChain é refletida por TypeInfoResolver e vice-versa.

Serializar campos de enumeração como cadeias de caracteres

Por padrão, as enumerações são serializadas como números. Para serializar os campos específicos de uma enumeração como cadeias de caracteres ao usar a geração de origem, anote-os com o conversor JsonStringEnumConverter<TEnum>. Ou para definir uma política global para todas as enumerações, use o atributo JsonSourceGenerationOptionsAttribute.

Conversor JsonStringEnumConverter<T>

Para serializar nomes de enumeração como cadeias de caracteres utilizando a geração de fonte, use o conversor JsonStringEnumConverter<TEnum>. (Não há suporte para o tipo JsonStringEnumConverter não genérico no runtime de AOT Nativa)

Anote o tipo de enumeração com o conversor JsonStringEnumConverter<TEnum> usando o atributo 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
}

Crie uma classe JsonSerializerContext e anote-a com o atributo JsonSerializableAttribute:

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

O código a seguir serializa os nomes de enumeração em vez dos valores numéricos:

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

O JSON resultante é semelhante ao seguinte exemplo:

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

Política ampla

Em vez de usar o tipo JsonStringEnumConverter<TEnum>, você poderá aplicar uma política ampla para serializar enumerações como cadeias de caracteres usando o JsonSourceGenerationOptionsAttribute. Crie uma classe JsonSerializerContext e anote-a com os atributos JsonSerializableAttributee JsonSourceGenerationOptionsAttribute:

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

Observe que a enumeração não possui o 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
}

Confira também