System.Text.Json でソース生成を使用する方法
System.Text.Json でのソース生成は、.NET 6 以降のバージョンで可能です。 ソースの生成は、"メタデータ コレクション" と "シリアル化の最適化" という 2 つのモードで構成されます。
ソース生成の既定値を使用する
すべての既定値を使用してソース生成を使用する場合 (両方のモード、既定のオプション):
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
{
}
WeatherForecast
メンバーの型は、[JsonSerializable]
属性で明示的に指定する必要はありません。 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 プロパティを使用して、このプロパティに別の名前を指定できます。
シリアル化の例
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);
逆シリアル化の例
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
の独自のインスタンスを渡すことができるメソッドを呼び出した場合、JsonSourceGenerationOptionsAttribute.WriteIndented
オプションの代わりにライターの Indented 設定が受け入れられます。
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
インスタンスをコンストラクターに渡します。 - コンテキスト インスタンスまたは
TypeInfo<TValue>
を受け取るJsonSerializer
のシリアル化または逆シリアル化のメソッドを呼び出します。
次に示すのは、コンテキスト クラスの例と、シリアル化および逆シリアル化のコード例です。
[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 アプリの場合:
ソース生成コンテキストまたは
TypeInfo<TValue>
を受け取る HttpClientJsonExtensions.GetFromJsonAsync と HttpClientJsonExtensions.PostAsJsonAsync の拡張メソッドのオーバーロードを使用します。Razor Pages、MVC、SignalR、Web API アプリ:
次の例のように、JsonSerializerOptions の AddContext メソッドを使用します。
[JsonSerializable(typeof(WeatherForecast[]))] internal partial class MyJsonContext : JsonSerializerContext { }
services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.AddContext<MyJsonContext>());
関連項目
- 新しい System.Text.Json ソース ジェネレーターを使ってみる
- .NET での JSON のシリアル化と逆シリアル化 - 概要
- ライブラリを使用する方法
- JsonSerializerOptions インスタンスのインスタンスを作成する
- 大文字と小文字を区別しない一致を有効にする
- プロパティの名前と値をカスタマイズする
- プロパティを無視する
- 無効な JSON を許可する
- オーバーフロー JSON を処理するか、JsonElement または JsonNode を使用する
- 参照を保持し、循環参照を処理する
- 変更できない型と非パブリック アクセサーに逆シリアル化する
- ポリモーフィックなシリアル化
- Newtonsoft.Json から System.Text.Json に移行する方法
- 文字エンコードをカスタマイズする
- DOM、Utf8JsonReader、Utf8JsonWriter を使用する
- JSON シリアル化のためのカスタム コンバーターの作成
- DateTime および DateTimeOffset のサポート
- System.Text.Json でサポートされているコレクション型
- System.Text.Json API リファレンス
- System.Text.Json.Serialization API リファレンス