Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este artigo mostra como usar a serialização com suporte à geração de código-fonte 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):
Crie uma classe parcial que deriva de JsonSerializerContext.
Especifique o tipo para serializar ou desserializar aplicando JsonSerializableAttribute à classe de contexto.
Chame um método JsonSerializer que:
- Usa uma instância JsonTypeInfo<T> ou
- Usa uma instância JsonSerializerContext ou
- Recebe uma instância JsonSerializerOptions e você definiu sua propriedade JsonSerializerOptions.TypeInfoResolver como a propriedade
Defaultdo tipo de contexto.
Por padrão, ambos os modos de geração de origem (otimização baseada em metadados e serialização) 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.
Este é o tipo usado nos seguintes exemplos:
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 origem para a classe anterior WeatherForecast :
[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, ele pode ter boolean e int objetos:
WeatherForecast wf = new() { Data = true, DataList = [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 código-fonte
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>(weatherForecast, sourceGenOptions);
Exemplos de desserialização
Usando JsonTypeInfo<T>:
weatherForecast = JsonSerializer.Deserialize(
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<WeatherForecast>(jsonString, sourceGenOptions);
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(
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<WeatherForecast>(jsonString, sourceGenOptions);
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>(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 modo baseado em metadados ou modo de serialização-otimizaçã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.
- Para um contexto inteiro, use a propriedade JsonSourceGenerationOptionsAttribute.GenerationMode.
- Para um tipo individual, use a propriedade JsonSerializableAttribute.GenerationMode.
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":25,"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));
Observação
JsonSourceGenerationMode.SerializationNão há suporte para serialização assíncrona ou serialização de caminho rápido . Embora 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 predeterminado do buffer. 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 a serialização baseada em reflexão fará com que uma InvalidOperationException mensagem descritiva seja lançada em runtime.
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.Serializeque usa umTypeInfo<TValue>. Passe a propriedadeDefault.<TypeName>da classe de contexto:jsonString = JsonSerializer.Serialize( weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);Um método
JsonSerializer.Serializeque usa um contexto. Passe a propriedade estáticaDefaultde 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.
O código a seguir mostra 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"
//}
}
}
}
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 JsonSerializableAttributee JsonSourceGenerationOptionsAttribute atributos:
[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
}
Nomes de membros de enumeração personalizados
A partir do .NET 9, você pode personalizar nomes de membros de enumeração usando o atributo JsonStringEnumMemberName attribute. Para obter mais informações, consulte Nomes de membros de enumeração personalizados.