次の方法で共有


System.Text.Json ソース ジェネレーターのフォールバック

JsonSerializerを受け入れるJsonSerializerOptionsメソッドのいずれかを使用する場合、System.Text.Json ソース ジェネレーターは認識されない型のリフレクション ベースのシリアル化に暗黙的にフォールバックしなくなります。

以前の動作

.NET 6 の次のソース生成の例を考えてみましょう。

JsonSerializer.Serialize(new Poco2(), typeof(Poco2), MyContext.Default);

[JsonSerializable(typeof(Poco1))]
public partial class MyContext : JsonSerializerContext {}

public class Poco1 { }
public class Poco2 { }

シリアル化可能な型MyContextPoco2が含まれていないため、シリアル化は次の例外で正しく失敗します。

System.InvalidOperationException:

'Metadata for type 'Poco2' was not provided to the serializer. The serializer method used does not 
support reflection-based creation of serialization-related type metadata. If using source generation, 
ensure that all root types passed to the serializer have been indicated with 'JsonSerializableAttribute', 
along with any types that might be serialized polymorphically.

次に、ソース ジェネレーターによって構築された MyContext インスタンスを使用して同じ型 (JsonSerializerOptions) をシリアル化しようとする次の呼び出しについて考えてみましょう。

JsonSerializer.Serialize(new Poco2(), MyContext.Default.Options);

オプション インスタンスには、既定のリフレクションベースの契約リゾルバーがフォールバックメカニズムとして静かに組み込まれています。そのため、型はリフレクションを使用して正常にシリアル化されます。

JsonSerializerOptions.GetConverter(Type)にアタッチされているオプション インスタンスのJsonSerializerContextにも、同じフォールバック ロジックが適用されます。 次のステートメントは、組み込みのリフレクション コンバーターを使用してコンバーターを返します。

JsonConverter converter = MyContext.Default.Options.GetConverter(typeof(Poco2));

新しい動作

.NET 7 以降では、次の呼び出しは、InvalidOperationException オーバーロードを使用する場合と同じ例外 (JsonSerializerContext) で失敗します。

JsonSerializer.Serialize(new Poco2(), MyContext.Default.Options);

さらに、次のステートメントは NotSupportedExceptionで失敗します。

JsonConverter converter = MyContext.Default.Options.GetConverter(typeof(Poco2));

導入されたバージョン

.NET 7

破壊的変更の種類

この変更は 、バイナリの互換性に影響する可能性があります。

変更の理由

以前の動作は、最小の驚きの原則に違反し、最終的にはソース生成の目的を打ち負かします。 型の JSON シリアル化コントラクトをカスタマイズできる機能のリリースにより、コントラクト メタデータのソースを微調整できます。 これを念頭に置いて、代替ソースをサイレントに導入することは、さらに望ましくなくなります。

以前の動作 (意図的または意図しない) に依存する場合があります。 推奨されるアクションは、すべての型の依存関係が含まれるように JsonSerializerContext 定義を更新することです。

[JsonSerializable(typeof(Poco1))]
[JsonSerializable(typeof(Poco2))]
public partial class MyContext : JsonSerializerContext {}

これにより、トリミングの安全性など、ソース生成の利点をアプリケーションで最大限に活用できます。

ただし、特定のケースでは、このような変更を行うのが実用的または不可能な場合があります。 お勧めしませんが、ソース生成シリアライザーでリフレクション フォールバックを再度有効にする方法はいくつかあります。

カスタム コントラクト リゾルバーを使用する

新しいコントラクトカスタマイズ機能を使用して、必要に応じてリフレクションベースの解像度にフォールバックするカスタム コントラクト リゾルバーを構築できます。

var options = new JsonSerializerOptions
{
     TypeInfoResolver = JsonTypeInfoResolver.Combine(MyContext.Default, new DefaultJsonTypeInfoResolver());
}

JsonSerializer.Serialize(new Poco2(), options); // Contract resolution falls back to the default reflection-based resolver.
options.GetConverter(typeof(Poco2)); // Returns the reflection-based converter.

AppContext スイッチを使用する

.NET 7 以降では、提供されている AppContext 互換性スイッチを使用して、リフレクション フォールバックをグローバルに再度有効にすることができます。 アプリケーションのプロジェクト ファイルに次のエントリを追加して、アプリでソースによって生成されたすべてのコンテキストに対してリフレクション フォールバックを再度有効にします。 AppContext スイッチの使用方法の詳細については、 .NET ランタイム構成設定に関する記事を参照してください。

<ItemGroup>
  <RuntimeHostConfigurationOption Include="System.Text.Json.Serialization.EnableSourceGenReflectionFallback" Value="true" />
</ItemGroup>

影響を受ける API