如何在 System.Text.Json 中使用源生成
System.Text.Json 中的源生成在 .NET 6 及更高版本中提供。 源生成由两种模式组成:元数据集合和序列化优化。
使用源生成默认值
若要将源生成用于所有默认值(两种模式,默认选项):
创建一个从 JsonSerializerContext 派生的分部类。
通过向上下文类应用 JsonSerializableAttribute 来指定要序列化或反序列化的类型。
调用 JsonSerializer 方法:
- 采用 JsonTypeInfo<T> 实例,或
- 采用 JsonSerializerContext 实例,或
- 采用 JsonSerializerOptions 实例,并且已将其 JsonSerializerOptions.TypeInfoResolver 属性设置为上下文类型的
Default
属性(.NET 7 及更高版本)。
默认情况下,如果未指定源生成模式,则会使用这两种源生成模式。 若要了解如何指定要使用的模式,请参阅本文后面的 指定源生成模式。
下面是以下示例中使用的类型:
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
下面是配置为针对上述 WeatherForecast
类执行源生成的上下文类:
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SourceGenerationContext : JsonSerializerContext
{
}
无需使用 [JsonSerializable]
属性显式指定 WeatherForecast
成员的类型。 声明为 object
的成员是此规则的例外。 需要指定声明为 object
的成员的运行时类型。 例如,假设有以下类:
public class WeatherForecast
{
public object? Data { get; set; }
public List<object>? DataList { get; set; }
}
你知道,在运行时,它可能有 boolean
和 int
对象:
WeatherForecast wf = new() { Data = true, DataList = new List<object> { true, 1 } };
其次,必须将 boolean
和 int
声明为 [JsonSerializable]
:
[JsonSerializable(typeof(WeatherForecast))]
[JsonSerializable(typeof(bool))]
[JsonSerializable(typeof(int))]
public partial class WeatherForecastContext : JsonSerializerContext
{
}
若要指定集合的源生成,请将 [JsonSerializable]
与集合类型一起使用。 例如:[JsonSerializable(typeof(List<WeatherForecast>))]
。
使用源生成的 JsonSerializer
方法
在以下示例中,上下文类型的静态 Default
属性提供具有默认选项的上下文类型的实例。 上下文实例提供返回 JsonTypeInfo<WeatherForecast>
实例的 WeatherForecast
属性。 可以使用 [JsonSerializable]
特性的 TypeInfoPropertyName 属性为此属性指定其他名称。
序列化示例
使用 JsonTypeInfo<T>:
jsonString = JsonSerializer.Serialize(
weatherForecast!, SourceGenerationContext.Default.WeatherForecast);
jsonString = JsonSerializer.Serialize(
weatherForecast, typeof(WeatherForecast), SourceGenerationContext.Default);
sourceGenOptions = new JsonSerializerOptions
{
TypeInfoResolver = SourceGenerationContext.Default
};
jsonString = JsonSerializer.Serialize(
weatherForecast, typeof(WeatherForecast), sourceGenOptions);
反序列化示例
使用 JsonTypeInfo<T>:
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(
jsonString, SourceGenerationContext.Default.WeatherForecast);
weatherForecast = JsonSerializer.Deserialize(
jsonString, typeof(WeatherForecast), SourceGenerationContext.Default)
as WeatherForecast;
var sourceGenOptions = new JsonSerializerOptions
{
TypeInfoResolver = SourceGenerationContext.Default
};
weatherForecast = JsonSerializer.Deserialize(
jsonString, typeof(WeatherForecast), sourceGenOptions)
as WeatherForecast;
完整的程序示例
下面是上述示例在完整程序中的情况:
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"}
}
}
}
指定源生成模式
可以为完整上下文指定元数据收集模式或序列化优化模式,其中可能包括多个类型。 也可以为单个类型指定模式。 如果同时执行这两项操作,则类型的模式规范将优先。
- 对于完整上下文,请使用 JsonSourceGenerationOptionsAttribute.GenerationMode 属性。
- 对于单个类型,请使用 JsonSerializableAttribute.GenerationMode 属性。
序列化优化模式示例
对于完整上下文:
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)] [JsonSerializable(typeof(WeatherForecast))] internal partial class SerializeOnlyContext : JsonSerializerContext { }
对于单个类型:
[JsonSerializable(typeof(WeatherForecast), GenerationMode = JsonSourceGenerationMode.Serialization)] internal partial class SerializeOnlyWeatherForecastOnlyContext : JsonSerializerContext { }
完整的程序示例
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"} } } }
元数据收集模式示例
对于完整上下文:
[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);
对于单个类型:
[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);
完整的程序示例
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"} } } }
指定序列化优化模式的选项
使用 JsonSourceGenerationOptionsAttribute 指定序列化优化模式支持的选项。 可以使用这些选项,但不会造成回退到 JsonSerializer
代码。 例如,WriteIndented
和 CamelCase
受支持:
[JsonSourceGenerationOptions(
WriteIndented = true,
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
GenerationMode = JsonSourceGenerationMode.Serialization)]
[JsonSerializable(typeof(WeatherForecast))]
internal partial class SerializationModeOptionsContext : JsonSerializerContext
{
}
使用 JsonSourceGenerationOptionsAttribute
指定序列化选项时,调用以下一种序列化方法:
采用
TypeInfo<TValue>
的JsonSerializer.Serialize
方法。 将上下文类的Default.<TypeName>
属性传递给它:jsonString = JsonSerializer.Serialize( weatherForecast, SerializationModeOptionsContext.Default.WeatherForecast);
采用上下文的
JsonSerializer.Serialize
方法。 将上下文类的Default
静态属性传递给它。jsonString = JsonSerializer.Serialize( weatherForecast, typeof(WeatherForecast), SerializationModeOptionsContext.Default);
如果调用的方法允许传递你自己的 Utf8JsonWriter
的实例,则会采用编写器的 Indented 设置,而不是 JsonSourceGenerationOptionsAttribute.WriteIndented
选项。
如果通过调用采用 JsonSerializerOptions
实例的构造函数来创建和使用上下文实例,则会使用提供的实例,而不是 JsonSourceGenerationOptionsAttribute
指定的选项。
下面是上述示例在完整程序中的情况:
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"
//}
}
}
}
使用 JsonSerializerOptions
指定选项
序列化优化模式不支持 JsonSerializerOptions 的一些选项。 此类选项会导致回退到非源生成的 JsonSerializer
代码。 有关详细信息,请参阅序列化优化。
若要通过使用 JsonSerializerOptions 指定选项:
- 创建
JsonSerializerOptions
的实例。 - 创建派生自 JsonSerializerContext 的类的实例,并将
JsonSerializerOptions
实例传递给构造函数。 - 调用
JsonSerializer
的序列化或反序列化方法(采用上下文实例或TypeInfo<TValue>
)。
下面是一个示例上下文类,后跟序列化和反序列化示例代码:
[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;
下面是上述示例在完整程序中的情况:
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"}
}
}
}
ASP.NET Core 中的源生成支持
在 Blazor 应用中:
使用 HttpClientJsonExtensions.GetFromJsonAsync 和 HttpClientJsonExtensions.PostAsJsonAsync 扩展方法(采用源生成上下文或
TypeInfo<TValue>
)的重载。在 Razor Pages、MVC、SignalR 和 Web API 应用中:
使用 JsonSerializerOptions 的 AddContext 方法,如以下示例所示:
[JsonSerializable(typeof(WeatherForecast[]))] internal partial class MyJsonContext : JsonSerializerContext { }
services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.AddContext<MyJsonContext>());
请参阅
.NET feedback
The .NET documentation is open source. Provide feedback here.
反馈
提交和查看相关反馈