Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Källgenerering i System.Text.Json är tillgängligt i .NET 6 och senare versioner. När den används i en app måste appens språkversion vara C# 9.0 eller senare. Den här artikeln visar hur du använder källgenereringsbaserad serialisering i dina appar.
Information om de olika källgenereringslägena finns i Källgenereringslägen.
Använd standardvärden för källgenerering
Om du vill använda källgenerering med alla standardvärden (båda lägena, standardalternativ):
Skapa en partiell klass som härleds från JsonSerializerContext.
Ange vilken typ som ska serialiseras eller deserialiseras genom att tillämpa JsonSerializableAttribute på kontextklassen.
Anropa en JsonSerializer metod som antingen:
- Tar en JsonTypeInfo<T> instans, eller
- Tar en JsonSerializerContext instans, eller
- Tar en JsonSerializerOptions-instans där du har angett dess JsonSerializerOptions.TypeInfoResolver-egenskap till
Default-egenskapen för kontexttypen (endast .NET 7 och senare).
Som standard används båda källgenereringslägena om du inte anger något. Information om hur du anger vilket läge som ska användas finns i Ange källgenereringsläge senare i den här artikeln.
Här är den typ som används i följande exempel:
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
Här är kontextklassen som konfigurerats för källgenerering för föregående WeatherForecast klass:
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SourceGenerationContext : JsonSerializerContext
{
}
Typerna av WeatherForecast medlemmar behöver inte uttryckligen anges med [JsonSerializable] attribut. Medlemmar som deklareras som object är ett undantag från den här regeln. Körningstypen för en medlem som deklarerats som object måste anges. Anta till exempel att du har följande klass:
public class WeatherForecast
{
public object? Data { get; set; }
public List<object>? DataList { get; set; }
}
Och du vet att den under körning kan ha boolean och int objekt:
WeatherForecast wf = new() { Data = true, DataList = new List<object> { true, 1 } };
Sedan boolean och int måste deklareras som [JsonSerializable]:
[JsonSerializable(typeof(WeatherForecast))]
[JsonSerializable(typeof(bool))]
[JsonSerializable(typeof(int))]
public partial class WeatherForecastContext : JsonSerializerContext
{
}
Om du vill ange källgenerering för en samling använder du [JsonSerializable] med samlingstypen. Exempel: [JsonSerializable(typeof(List<WeatherForecast>))].
JsonSerializer metoder som använder källgenerering
I följande exempel ger den statiska Default egenskapen för kontexttypen en instans av kontexttypen med standardalternativ. Kontextinstansen tillhandahåller en WeatherForecast egenskap som returnerar en JsonTypeInfo<WeatherForecast> instans. Du kan ange ett annat namn för den här egenskapen med hjälp TypeInfoPropertyName av egenskapen för attributet [JsonSerializable] .
Serialiseringsexempel
Att använda JsonTypeInfo<T>:
jsonString = JsonSerializer.Serialize(
weatherForecast!, SourceGenerationContext.Default.WeatherForecast);
Att använda JsonSerializerContext:
jsonString = JsonSerializer.Serialize(
weatherForecast, typeof(WeatherForecast), SourceGenerationContext.Default);
Att använda JsonSerializerOptions:
sourceGenOptions = new JsonSerializerOptions
{
TypeInfoResolver = SourceGenerationContext.Default
};
jsonString = JsonSerializer.Serialize(
weatherForecast, typeof(WeatherForecast), sourceGenOptions);
Exempel på deserialisering
Att använda JsonTypeInfo<T>:
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
jsonString, SourceGenerationContext.Default.WeatherForecast);
Att använda JsonSerializerContext:
weatherForecast = JsonSerializer.Deserialize(
jsonString, typeof(WeatherForecast), SourceGenerationContext.Default)
as WeatherForecast;
Att använda JsonSerializerOptions:
var sourceGenOptions = new JsonSerializerOptions
{
TypeInfoResolver = SourceGenerationContext.Default
};
weatherForecast = JsonSerializer.Deserialize(
jsonString, typeof(WeatherForecast), sourceGenOptions)
as WeatherForecast;
Exempel på slutfört program
Här är de föregående exemplen i ett fullständigt program:
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"}
}
}
}
Ange källgenereringsläge
Du kan ange metadatabaserat läge eller serialiseringsoptimeringsläge för en hel kontext, som kan innehålla flera typer. Eller så kan du ange läget för en enskild typ. Om du gör båda vinner lägesspecifikationen för en typ.
- För hela kontexten, använd egenskapen JsonSourceGenerationOptionsAttribute.GenerationMode.
- Använd egenskapen JsonSerializableAttribute.GenerationMode för en enskild typ.
Exempel på serialiseringsoptimering (snabb sökväg)
För en hel kontext:
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(WeatherForecast))] internal partial class SerializeOnlyContext : JsonSerializerContext { }För en enskild typ:
[JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)] internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext { }Exempel på slutfört program
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"} } } }
Exempel på metadatabaserat läge
För en hel 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);För en enskild typ:
[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);Exempel på slutfört program
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"} } } }
Stöd för källgenerering i ASP.NET Core
I Blazor-appar använder du överbelastningar av HttpClientJsonExtensions.GetFromJsonAsync och HttpClientJsonExtensions.PostAsJsonAsync utökningsmetoder som tar en källgenereringskontext eller TypeInfo<TValue>.
Från och med .NET 8 kan du också använda överlagringar av HttpClientJsonExtensions.GetFromJsonAsAsyncEnumerable tilläggsmetoder som accepterar en källgenereringskontext eller TypeInfo<TValue>.
I Appar för Razor Pages, MVC, SignalR och Web API använder du JsonSerializerOptions.TypeInfoResolver egenskapen för att ange kontexten.
[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));
Kommentar
JsonSourceGenerationMode.Serialization, eller snabbvägsserialisering, stöds inte för asynkron serialisering.
I .NET 7 och tidigare versioner gäller den här begränsningen även synkrona överlagringar av JsonSerializer.Serialize som accepterar en Stream. Från och med .NET 8, även om strömningsserialisering kräver metadatabaserade modeller, kommer den att återgå till snabbväg om nyttolasten är känd för att vara tillräckligt liten för att få plats i den förutbestämda buffertstorleken. Mer information finns i https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/#json.
Inaktivera reflektionsstandardinställningar
Eftersom System.Text.Json använder reflektion som standard, kan anrop av en grundläggande serialiseringsmetod orsaka problem för Native AOT-appar, som inte har stöd för alla nödvändiga reflektions-API:er. Dessa stopp kan vara svåra att diagnostisera eftersom de kan vara oförutsägbara, och appar genomsöks ofta med hjälp av CoreCLR-runtime, där reflektion fungerar. Om du i stället uttryckligen inaktiverar reflektionsbaserad serialisering är det enklare att diagnostisera pauser. Kod som använder reflektionsbaserad serialisering kommer att kasta ett InvalidOperationException med ett beskrivande meddelande vid körningstid.
Om du vill inaktivera standardreflektion i din app anger du JsonSerializerIsReflectionEnabledByDefault egenskapen MSBuild till false i projektfilen:
<PropertyGroup>
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
- Beteendet för den här egenskapen är konsekvent oavsett vilken miljö som används, antingen CoreCLR eller Native AOT.
- Om du inte anger den här egenskapen och PublishTrimmed är aktiverat inaktiveras reflektionsbaserad serialisering automatiskt.
Du kan programmatiskt kontrollera om reflektion är inaktiverat med hjälp av egenskapen JsonSerializer.IsReflectionEnabledByDefault. Följande kodfragment visar hur du kan konfigurera serialiseraren beroende på om reflektion är aktiverat:
static JsonSerializerOptions CreateDefaultOptions()
{
return new()
{
TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault
? new DefaultJsonTypeInfoResolver()
: MyContext.Default
};
}
Eftersom egenskapen behandlas som en länktidskonstant, rotar inte den tidigare metoden den reflektionsbaserade lösaren i program som körs i Native AOT.
Ange alternativ
I .NET 8 och senare versioner kan de flesta alternativ som du kan ange med hjälp JsonSerializerOptions av också anges med hjälp av JsonSourceGenerationOptionsAttribute attributet. Fördelen med att ange alternativ via attributet är att konfigurationen anges vid kompileringstid, vilket säkerställer att den genererade MyContext.Default egenskapen är förkonfigurerad med alla relevanta alternativ inställda.
Följande kod visar hur du anger alternativ med hjälp av attributet JsonSourceGenerationOptionsAttribute .
[JsonSourceGenerationOptions(
WriteIndented = true,
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
GenerationMode = JsonSourceGenerationMode.Serialization)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SerializationModeOptionsContext : JsonSerializerContext
{
}
När du använder JsonSourceGenerationOptionsAttribute för att ange serialiseringsalternativ anropar du någon av följande serialiseringsmetoder:
En
JsonSerializer.Serializemetod som tar enTypeInfo<TValue>. Skicka egenskapenDefault.<TypeName>från din kontextklass:jsonString = JsonSerializer.Serialize( weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);En
JsonSerializer.Serializemetod som tar en kontext. Skicka den statiska egenskapenDefaultför din kontextklass.jsonString = JsonSerializer.Serialize( weatherForecast, typeof(WeatherForecast), SerializationModeOptionsContext.Default);
Om du anropar en metod som låter dig skicka in din egen instans av Utf8JsonWriter, respekteras författarens Indented inställning i stället för alternativet JsonSourceGenerationOptionsAttribute.WriteIndented .
Om du skapar och använder en kontextinstans genom att anropa konstruktorn som tar en JsonSerializerOptions instans används den angivna instansen i stället för de alternativ som anges av JsonSourceGenerationOptionsAttribute.
Här är de föregående exemplen i ett fullständigt program:
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"
//}
}
}
}
Kombinera källgeneratorer
Du kan kombinera kontrakt från flera källgenererade kontexter i en enda JsonSerializerOptions instans. Använd egenskapen JsonSerializerOptions.TypeInfoResolver för att länka flera kontexter som har kombinerats med hjälp JsonTypeInfoResolver.Combine(IJsonTypeInfoResolver[]) av metoden.
var options = new JsonSerializerOptions
{
TypeInfoResolver = JsonTypeInfoResolver.Combine(ContextA.Default, ContextB.Default, ContextC.Default),
};
Från och med .NET 8 kan du göra det med hjälp av JsonSerializerOptions.TypeInfoResolverChain egenskapen om du senare vill förbereda eller lägga till en annan kontext. Ordningen på kedjan är viktig: JsonSerializerOptions förfrågar var och en av lösarna i deras angivna ordning och returnerar det första resultatet som är icke-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.
Alla ändringar som görs i egenskapen TypeInfoResolverChain återspeglas av TypeInfoResolver och vice versa.
Serialisera uppräkningsfält som strängar
Som standard serialiseras enum-värden som tal. Om du vill serialisera ett specifikt enums fält som strängar när du använder källgenerering, ska du kommentera det med JsonStringEnumConverter<TEnum> konverteraren. För att ställa in en generell policy för alla uppräkningar, använd attributet JsonSourceGenerationOptionsAttribute.
JsonStringEnumConverter<T> omvandlare
Om du vill serialisera uppräkningsnamn som strängar med källgenerering använder du JsonStringEnumConverter<TEnum> konverteraren. (Den icke-generiska JsonStringEnumConverter typen stöds inte av Native AOT-runtime.)
Kommentera uppräkningstypen med JsonStringEnumConverter<TEnum> konverteraren med hjälp av JsonConverterAttribute attributet:
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
}
Skapa en JsonSerializerContext klass och kommentera den med attributet JsonSerializableAttribute :
[JsonSerializable(typeof(WeatherForecastWithPrecipEnum))]
public partial class Context1 : JsonSerializerContext { }
Följande kod serialiserar uppräkningsnamnen i stället för de numeriska värdena:
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);
Den resulterande JSON:en ser ut som i följande exempel:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Precipitation": "Sleet"
}
Övergripande princip
I stället för att använda typen JsonStringEnumConverter<TEnum> kan du använda en generell princip för att serialisera uppräkningar som strängar med hjälp av JsonSourceGenerationOptionsAttribute. Skapa en JsonSerializerContext klass och kommentera den med attributen JsonSerializableAttributeoch JsonSourceGenerationOptionsAttribute :
[JsonSourceGenerationOptions(UseStringEnumConverter = true)]
[JsonSerializable(typeof(WeatherForecast2WithPrecipEnum))]
public partial class Context2 : JsonSerializerContext { }
Observera att uppräkningen inte har 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
}
Anpassade Enum-medlemsnamn
Från och med .NET 9 kan du anpassa namn på uppräkningsmedlemmar med hjälp av attributet JsonStringEnumMemberName. Mer information finns i Anpassade uppräkningsmedlemsnamn.