Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V tomto článku se dozvíte, jak ve vašich aplikacích používat serializaci založenou na System.Text.Json generaci zdrojového kódu.
Informace o různých režimech generování zdroje najdete v tématu Režimy generování zdroje.
Použití výchozích hodnot generování zdrojového kódu
Použití generování zdroje se všemi výchozími nastaveními (oba režimy, výchozí možnosti):
Vytvořte částečnou třídu, která je odvozena od JsonSerializerContext.
Zadejte typ pro serializaci nebo deserializaci použitím JsonSerializableAttribute třídy kontextu.
Volejte metodu JsonSerializer, která buď:
- JsonTypeInfo<T> Přebírá instanci nebo
- JsonSerializerContext Přebírá instanci nebo
- Vezme JsonSerializerOptions instanci a jeho vlastnost jste nastavili JsonSerializerOptions.TypeInfoResolver na
Defaultvlastnost typu kontextu.
Ve výchozím nastavení se používají oba režimy generování zdroje (optimalizace založené na metadatech i serializaci), pokud ho nezadáte. Informace o tom, jak určit režim, který se má použít, naleznete v části Určení režimu generování zdroje dále v tomto článku.
Tady je typ, který se používá v následujících příkladech:
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
Tady je kontextová třída nakonfigurovaná tak, aby vygenerovala zdroj pro předchozí WeatherForecast třídu:
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SourceGenerationContext : JsonSerializerContext { }
Typy WeatherForecast členů není nutné explicitně zadávat pomocí [JsonSerializable] atributů. Členové deklarovaní jako object jsou výjimkou z tohoto pravidla. Je třeba specifikovat typ za běhu pro člena deklarovaného jako object. Předpokládejme například, že máte následující třídu:
public class WeatherForecast
{
public object? Data { get; set; }
public List<object>? DataList { get; set; }
}
A víte, že za běhu může mít boolean a int objekty:
WeatherForecast wf = new() { Data = true, DataList = [true, 1] };
Pak boolean a int jsou nutné deklarovat jako [JsonSerializable]:
[JsonSerializable(typeof(WeatherForecast))]
[JsonSerializable(typeof(bool))]
[JsonSerializable(typeof(int))]
public partial class WeatherForecastContext : JsonSerializerContext
{
}
Chcete-li zadat generování zdroje pro kolekci, použijte [JsonSerializable] s typem kolekce. Například: [JsonSerializable(typeof(List<WeatherForecast>))].
JsonSerializer metody, které používají generování zdroje
V následujících příkladech statická Default vlastnost typu kontextu poskytuje instanci typu kontextu s výchozími možnostmi. Instance kontextu poskytuje WeatherForecast vlastnost, která vrací JsonTypeInfo<WeatherForecast> instanci. Pro tuto vlastnost můžete zadat jiný název pomocí TypeInfoPropertyName vlastnosti atributu [JsonSerializable] .
Příklady serializace
Pomocí JsonTypeInfo<T>:
jsonString = JsonSerializer.Serialize(
weatherForecast!, SourceGenerationContext.Default.WeatherForecast);
Pomocí JsonSerializerContext:
jsonString = JsonSerializer.Serialize(
weatherForecast, typeof(WeatherForecast), SourceGenerationContext.Default);
Pomocí JsonSerializerOptions:
sourceGenOptions = new JsonSerializerOptions
{
TypeInfoResolver = SourceGenerationContext.Default
};
jsonString = JsonSerializer.Serialize<WeatherForecast>(weatherForecast, sourceGenOptions);
Příklady deserializace
Pomocí JsonTypeInfo<T>:
weatherForecast = JsonSerializer.Deserialize(
jsonString, SourceGenerationContext.Default.WeatherForecast);
Pomocí JsonSerializerContext:
weatherForecast = JsonSerializer.Deserialize(
jsonString, typeof(WeatherForecast), SourceGenerationContext.Default)
as WeatherForecast;
Pomocí JsonSerializerOptions:
var sourceGenOptions = new JsonSerializerOptions
{
TypeInfoResolver = SourceGenerationContext.Default
};
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, sourceGenOptions);
Příklad kompletního programu
Tady jsou předchozí příklady v úplném programu:
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"}
}
}
}
Určení režimu generování zdroje
Můžete zadat režim založený na metadatech nebo režim optimalizace serializace pro celý kontext, který může obsahovat více typů. Nebo můžete určit režim pro jednotlivé typy. Pokud provedete obojí, specifikace režimu pro typ vyhrává.
- Pro celý kontext použijte JsonSourceGenerationOptionsAttribute.GenerationMode vlastnost.
- Pro jednotlivé typy použijte JsonSerializableAttribute.GenerationMode vlastnost.
Příklad režimu optimalizace serializace (rychlá cesta)
Pro celý kontext:
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(WeatherForecast))] internal partial class SerializeOnlyContext : JsonSerializerContext { }Pro jednotlivé typy:
[JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)] internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext { }Příklad kompletního 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"} } } }
Příklad režimu založeného na metadatech
Pro celý kontext:
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)] [JsonSerializable(typeof(WeatherForecast))] internal partial class MetadataOnlyContext : JsonSerializerContext { }jsonString = JsonSerializer.Serialize( weatherForecast, MetadataOnlyContext.Default.WeatherForecast);weatherForecast = JsonSerializer.Deserialize<WeatherForecast>( jsonString, MetadataOnlyContext.Default.WeatherForecast);Pro jednotlivé typy:
[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);Příklad kompletního 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":25,"Summary":"Hot"} } } }
Podpora generování zdrojového kódu v ASP.NET Core
V aplikacích Blazor použijte přetížení rozšiřujících metod HttpClientJsonExtensions.GetFromJsonAsync a HttpClientJsonExtensions.PostAsJsonAsync, které využívají kontext generování zdroje nebo TypeInfo<TValue>.
Počínaje .NET 8 můžete také použít přetížené varianty rozšiřujících metod HttpClientJsonExtensions.GetFromJsonAsAsyncEnumerable, které přijímají kontext generování zdroje nebo TypeInfo<TValue>.
V aplikacích Razor Pages, MVC, SignalR a Web API použijte JsonSerializerOptions.TypeInfoResolver vlastnost k určení kontextu.
[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));
Poznámka:
JsonSourceGenerationMode.Serializationserializace rychlým postupem není podporována pro asynchronní serializaci. I když streamovaná serializace vyžaduje modely založené na metadatech, zvolí rychlou cestu, pokud jsou části známé jako dostatečně malé, aby se vešly do předem stanovené velikosti vyrovnávací paměti. Další informace najdete na webu https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/#json.
Zakázat výchozí hodnoty reflexe
Volání základní metody serializace může narušit nativní aplikace AOT, které nepodporují všechna požadovaná reflexní API, protože System.Text.Json používá reflexi ve výchozím nastavení. Tyto přestávky můžou být náročné diagnostikovat, protože můžou být nepředvídatelné a aplikace se často ladí pomocí modulu runtime CoreCLR, kde funguje reflexe. Pokud místo toho explicitně zakážete serializaci založenou na reflexi, je snazší diagnostikovat problémy. Kód, který používá serializaci založenou na reflexi, způsobí InvalidOperationException vyvolání popisné zprávy za běhu.
Pokud chcete ve své aplikaci zakázat výchozí reflexi, nastavte JsonSerializerIsReflectionEnabledByDefault vlastnost MSBuild do false souboru projektu:
<PropertyGroup>
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
- Chování této vlastnosti je konzistentní bez ohledu na modul runtime, buď CoreCLR, nebo nativní AOT.
- Pokud tuto vlastnost nezadáte a funkce PublishTrimmed je povolená , serializace založená na reflexi se automaticky zakáže.
Pomocí této vlastnosti můžete programově zkontrolovat, jestli je reflexe zakázaná JsonSerializer.IsReflectionEnabledByDefault . Následující fragment kódu ukazuje, jak můžete serializátor nakonfigurovat v závislosti na tom, jestli je reflexe povolená:
static JsonSerializerOptions CreateDefaultOptions()
{
return new()
{
TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault
? new DefaultJsonTypeInfoResolver()
: MyContext.Default
};
}
Vzhledem k tomu, že vlastnost je považována za konstantu v době linkování, předchozí metoda nezakoření řešitel založený na reflexi v aplikacích, které běží v nativním AOT.
Zadání možností
V .NET 8 a novějších verzích lze většinu možností, které můžete použít JsonSerializerOptions , nastavit také pomocí atributu JsonSourceGenerationOptionsAttribute . Výhodou nastavení možností prostřednictvím atributu je to, že konfigurace je určena v době kompilace, což zajišťuje, že vygenerovaná MyContext.Default vlastnost je předem nakonfigurovaná se všemi příslušnými sadami možností.
Následující kód ukazuje, jak nastavit možnosti pomocí atributu JsonSourceGenerationOptionsAttribute .
[JsonSourceGenerationOptions(
WriteIndented = true,
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
GenerationMode = JsonSourceGenerationMode.Serialization)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SerializationModeOptionsContext : JsonSerializerContext
{
}
Při použití JsonSourceGenerationOptionsAttribute k určení možností serializace, zavolejte jednu z následujících metod serializace:
Metoda
JsonSerializer.Serialize, která přebíráTypeInfo<TValue>. Předejte vlastnostDefault.<TypeName>vaší třídy kontextu:jsonString = JsonSerializer.Serialize( weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);Metoda
JsonSerializer.Serialize, která přebírá kontext. PředatDefaultstatickou vlastnost vaší třídy kontextu.jsonString = JsonSerializer.Serialize( weatherForecast, typeof(WeatherForecast), SerializationModeOptionsContext.Default);
Pokud voláte metodu, která umožňuje předat vlastní instanci Utf8JsonWriter, respektuje se nastavení zapisovače Indented namísto možnosti JsonSourceGenerationOptionsAttribute.WriteIndented.
Pokud vytvoříte a použijete kontextovou instanci voláním konstruktoru JsonSerializerOptions , který přebírá instanci, bude zadaná instance použita místo možností určených JsonSourceGenerationOptionsAttribute.
Následující kód ukazuje předchozí příklady v úplném programu:
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"
//}
}
}
}
Kombinování generátorů zdrojů
Kontrakty z několika kontextů vygenerovaných zdrojem můžete kombinovat v jedné JsonSerializerOptions instanci. JsonSerializerOptions.TypeInfoResolver Pomocí vlastnosti zřetězte více kontextů, které byly kombinovány pomocí JsonTypeInfoResolver.Combine(IJsonTypeInfoResolver[]) metody.
var options = new JsonSerializerOptions
{
TypeInfoResolver = JsonTypeInfoResolver.Combine(ContextA.Default, ContextB.Default, ContextC.Default),
};
Počínaje rozhraním .NET 8, pokud později chcete předřadit nebo připojit jiný kontext, můžete to provést pomocí JsonSerializerOptions.TypeInfoResolverChain vlastnosti. Řazení řetězce je významné: JsonSerializerOptions dotazuje se na každý z překladačů v zadaném pořadí a vrátí první výsledek, který není 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.
Jakákoliv změna provedená ve vlastnosti TypeInfoResolverChain se projeví ve TypeInfoResolver a naopak.
Serializujte výčtová pole jako řetězce
Ve výchozím nastavení jsou výčty serializovány jako čísla. Pokud chcete serializovat pole určitého výčtu jako řetězce při použití generování kódu, anotujte jej pomocí konvertoru JsonStringEnumConverter<TEnum>. Nebo pro nastavení plošné zásady pro všechny výčty použijte atribut JsonSourceGenerationOptionsAttribute.
JsonStringEnumConverter<T> převodník
Chcete-li serializovat názvy výčtů jako řetězce pomocí generování zdroje, použijte JsonStringEnumConverter<TEnum> převaděč. (Nativní modul runtime AOT nepodporuje negenerický JsonStringEnumConverter typ.)
Anotujte typ výčtu pomocí převaděče JsonStringEnumConverter<TEnum> pomocí atributu 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
}
Vytvořte JsonSerializerContext třídu a označte ji pomocí atributu JsonSerializableAttribute :
[JsonSerializable(typeof(WeatherForecastWithPrecipEnum))]
public partial class Context1 : JsonSerializerContext { }
Následující kód serializuje názvy výčtů místo číselných hodnot:
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);
Výsledný json vypadá jako v následujícím příkladu:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Precipitation": "Sleet"
}
Zásady deky
Místo použití typu JsonStringEnumConverter<TEnum> můžete použít globální zásady k serializaci výčtů jako řetězce pomocí JsonSourceGenerationOptionsAttribute. Vytvořte JsonSerializerContext třídu a označte ji poznámkami JsonSerializableAttributea JsonSourceGenerationOptionsAttribute atributy:
[JsonSourceGenerationOptions(UseStringEnumConverter = true)]
[JsonSerializable(typeof(WeatherForecast2WithPrecipEnum))]
public partial class Context2 : JsonSerializerContext { }
Všimněte si, že výčet nemá 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
}
Vlastní názvy členů výčtu
Od verze .NET 9 můžete přizpůsobit názvy členů výčtu pomocí atributu JsonStringEnumMemberName. Další informace naleznete v tématu Vlastní názvy členů výčtu.