Newtonsoft.Json から System.Text.Json に移行する
この記事では、Newtonsoft.Json から System.Text.Json に移行する方法を示します。
System.Text.Json
名前空間は、JavaScript Object Notation (JSON) との間でのシリアル化と逆シリアル化の機能を提供します。 System.Text.Json
ライブラリは、.NET Core 3.1 以降のバージョン用のランタイムに含まれています。 その他のターゲット フレームワークの場合は、System.Text.Json NuGet パッケージをインストールします。 このパッケージで以下がサポートされます。
- .NET Standard 2.0 以降のバージョン
- .NET Framework 4.6.2 およびそれ以降のバージョン
- .NET Core 2.0、2.1、および 2.2
ヒント
AI 支援を使用して、GitHub Copilot で Newtonsoft.Json
から移行できます。
System.Text.Json
は、主にパフォーマンス、セキュリティ、標準への準拠に焦点を当てています。 これには既定の動作について重要な違いがいくつかあり、Newtonsoft.Json
との機能パリティを持つことがこの目的ではありません。 一部のシナリオでは、現在 System.Text.Json
に組み込み機能がなくても、推奨される回避策があります。 それ以外のシナリオでは、回避策は実用的ではありません。
System.Text.Json
チームは、最も頻繁に要求される機能の追加に注力しています。 お使いのアプリケーションで、欠如している機能を利用する必要がある場合は、シナリオのサポートを追加できるかどうかを確認するために、dotnet/runtime GitHub リポジトリでイシューを提出することを検討してください。
この記事のほとんどの内容は、JsonSerializer API の使用方法に関するものですが、JsonDocument (ドキュメント オブジェクト モデル: DOM を表します)、Utf8JsonReader、Utf8JsonWriter の型の使用方法に関するガイダンスも含まれています。
Visual Basic では Utf8JsonReader を使用できません。すなわち、カスタム コンバーターも記述できません。 ここで提示する回避策の多くでは、カスタム コンバーターを記述する必要があります。 C# でカスタム コンバーターを記述し、それを Visual Basic プロジェクトに登録できます。 詳細については、「Visual Basic のサポート」をご覧ください。
相違点のテーブル
次の表は、Newtonsoft.Json
の機能と、それと同等の System.Text.Json
の機能を一覧にしたものです。 同等機能は次のカテゴリに分けられます。
- ✔️ 組み込み機能によってサポートされています。
System.Text.Json
で同様の動作を得るには、属性またはグローバル オプションの使用が必要になる場合があります。 - ⚠ サポートされていませんが、回避策を適用できます。 回避策はカスタム コンバーターですが、
Newtonsoft.Json
の機能と完全に等価ではない可能性があります。 これらの一部については、サンプル コードが例として提供されます。Newtonsoft.Json
のこれらの機能を利用する必要がある場合、移行するには、.NET オブジェクト モデルに対する変更やその他のコード変更が必要になります。 - ❌ サポートされていません。回避策は実用的でないか不可能です。
Newtonsoft.Json
のこれらの機能を利用する必要がある場合、移行を可能にするには大幅な変更が必要です。
Newtonsoft.Json の機能 | System.Text.Json での同等機能 |
---|---|
既定での大文字と小文字の区別のない逆シリアル化 | ✔️ PropertyNameCaseInsensitive グローバル設定 |
キャメルケースのプロパティ名 | ✔️ PropertyNamingPolicy グローバル設定 |
スネークケースのプロパティ名 | ✔️ スネーク ケースの名前付けポリシー |
最小限の文字のエスケープ | ✔️ 厳密な文字エスケープ、構成可能 |
NullValueHandling.Ignore グローバル設定 |
✔️ DefaultIgnoreCondition グローバル オプション |
コメントを許可する | ✔️ ReadCommentHandling グローバル設定 |
末尾のコンマを許可する | ✔️ AllowTrailingCommas グローバル設定 |
カスタム コンバーターの登録 | ✔️ 優先順位の順序が異なる |
既定の最大深度は 64、構成可能 | ✔️ 既定の最大深度は 64、構成可能 |
PreserveReferencesHandling グローバル設定 |
✔️ ReferenceHandling グローバル設定 |
引用符で囲まれた数値をシリアル化または逆シリアル化する | ✔️ NumberHandling グローバル設定、[JsonNumberHandling] 属性 |
不変のクラスと構造体への逆シリアル化 | ✔️ JsonConstructor、C# 9 のレコード |
フィールドのサポート | ✔️ IncludeFields グローバル設定、[JsonInclude] 属性 |
DefaultValueHandling グローバル設定 |
✔️ DefaultIgnoreCondition グローバル設定 |
[JsonProperty] での NullValueHandling の設定 |
✔️ JsonIgnore 属性 |
[JsonProperty] での DefaultValueHandling の設定 |
✔️ JsonIgnore 属性 |
文字列以外のキーを含む Dictionary を逆シリアル化する |
✔️ Supported |
非パブリック プロパティのセッターとゲッターのサポート | ✔️ JsonInclude 属性 |
[JsonConstructor] 属性 |
✔️ [JsonConstructor] 属性 |
ReferenceLoopHandling グローバル設定 |
✔️ ReferenceHandling グローバル設定 |
コールバック | ✔️ コールバック |
NaN、Infinity、-Infinity | ✔️ Supported |
[JsonProperty] 属性での Required の設定 |
✔️ [JsonRequired] 属性と C# 必須修飾子 |
プロパティを無視するための DefaultContractResolver |
✔️ DefaultJsonTypeInfoResolver クラス |
ポリモーフィックなシリアル化 | ✔️ [JsonDerivedType] 属性 |
ポリモーフィックな逆シリアル化 | ✔️ [JsonDerivedType] 属性の型識別子 |
文字列列挙型の値を逆シリアル化する | ✔️ 文字列列挙型の値を逆シリアル化する |
MissingMemberHandling グローバル設定 |
✔️ 欠落しているメンバーを処理する |
セッターを持たないプロパティを設定する | ✔️ セッターを持たないプロパティを設定する |
ObjectCreationHandling グローバル設定 |
✔️ プロパティを置き換えるのではなく再利用する |
さまざまな型のサポート | ⚠ 一部の型にはカスタム コンバーターが必要 |
推論された型を object のプロパティに逆シリアル化する |
⚠ 非サポート、回避策、サンプル |
JSON の null リテラルを null 非許容値の型に逆シリアル化する |
⚠ 非サポート、回避策、サンプル |
DateTimeZoneHandling 、DateFormatString の設定 |
⚠ 非サポート、回避策、サンプル |
JsonConvert.PopulateObject メソッド |
⚠ 非サポート、回避策 |
System.Runtime.Serialization 属性のサポート |
⚠ 非サポート、回避策、サンプル |
JsonObjectAttribute |
⚠ 非サポート、回避策 |
引用符なしのプロパティ名を許可する | ❌デザインでサポートされていません |
文字列値を囲む単一引用符を許可する | ❌デザインでサポートされていません |
文字列のプロパティに対して文字列ではない JSON 値を許可する | ❌デザインでサポートされていません |
TypeNameHandling.All グローバル設定 |
❌デザインでサポートされていません |
JsonPath クエリのサポート |
❌サポートされていません |
構成可能な制限 | ❌サポートされていません |
Newtonsoft.Json の機能 | System.Text.Json での同等機能 |
---|---|
既定での大文字と小文字の区別のない逆シリアル化 | ✔️ PropertyNameCaseInsensitive グローバル設定 |
キャメルケースのプロパティ名 | ✔️ PropertyNamingPolicy グローバル設定 |
最小限の文字のエスケープ | ✔️ 厳密な文字エスケープ、構成可能 |
NullValueHandling.Ignore グローバル設定 |
✔️ DefaultIgnoreCondition グローバル オプション |
コメントを許可する | ✔️ ReadCommentHandling グローバル設定 |
末尾のコンマを許可する | ✔️ AllowTrailingCommas グローバル設定 |
カスタム コンバーターの登録 | ✔️ 優先順位の順序が異なる |
既定の最大深度は 64、構成可能 | ✔️ 既定の最大深度は 64、構成可能 |
PreserveReferencesHandling グローバル設定 |
✔️ ReferenceHandling グローバル設定 |
引用符で囲まれた数値をシリアル化または逆シリアル化する | ✔️ NumberHandling グローバル設定、[JsonNumberHandling] 属性 |
不変のクラスと構造体への逆シリアル化 | ✔️ JsonConstructor、C# 9 のレコード |
フィールドのサポート | ✔️ IncludeFields グローバル設定、[JsonInclude] 属性 |
DefaultValueHandling グローバル設定 |
✔️ DefaultIgnoreCondition グローバル設定 |
[JsonProperty] での NullValueHandling の設定 |
✔️ JsonIgnore 属性 |
[JsonProperty] での DefaultValueHandling の設定 |
✔️ JsonIgnore 属性 |
文字列以外のキーを含む Dictionary を逆シリアル化する |
✔️ Supported |
非パブリック プロパティのセッターとゲッターのサポート | ✔️ JsonInclude 属性 |
[JsonConstructor] 属性 |
✔️ [JsonConstructor] 属性 |
ReferenceLoopHandling グローバル設定 |
✔️ ReferenceHandling グローバル設定 |
コールバック | ✔️ コールバック |
NaN、Infinity、-Infinity | ✔️ Supported |
[JsonProperty] 属性での Required の設定 |
✔️ [JsonRequired] 属性と C# 必須修飾子 |
プロパティを無視するための DefaultContractResolver |
✔️ DefaultJsonTypeInfoResolver クラス |
ポリモーフィックなシリアル化 | ✔️ [JsonDerivedType] 属性 |
ポリモーフィックな逆シリアル化 | ✔️ [JsonDerivedType] 属性の型識別子 |
文字列列挙型の値を逆シリアル化する | ✔️ 文字列列挙型の値を逆シリアル化する |
さまざまな型のサポート | ⚠ 一部の型にはカスタム コンバーターが必要 |
推論された型を object のプロパティに逆シリアル化する |
⚠ 非サポート、回避策、サンプル |
JSON の null リテラルを null 非許容値の型に逆シリアル化する |
⚠ 非サポート、回避策、サンプル |
DateTimeZoneHandling 、DateFormatString の設定 |
⚠ 非サポート、回避策、サンプル |
JsonConvert.PopulateObject メソッド |
⚠ 非サポート、回避策 |
ObjectCreationHandling グローバル設定 |
⚠ 非サポート、回避策 |
セッターなしでコレクションに追加する | ⚠ 非サポート、回避策 |
スネークケースのプロパティ名 | ⚠ 非サポート、回避策 |
System.Runtime.Serialization 属性のサポート |
⚠ 非サポート、回避策、サンプル |
MissingMemberHandling グローバル設定 |
⚠ 非サポート、回避策、サンプル |
JsonObjectAttribute |
⚠ 非サポート、回避策 |
引用符なしのプロパティ名を許可する | ❌デザインでサポートされていません |
文字列値を囲む単一引用符を許可する | ❌デザインでサポートされていません |
文字列のプロパティに対して文字列ではない JSON 値を許可する | ❌デザインでサポートされていません |
TypeNameHandling.All グローバル設定 |
❌デザインでサポートされていません |
JsonPath クエリのサポート |
❌サポートされていません |
構成可能な制限 | ❌サポートされていません |
Newtonsoft.Json の機能 | System.Text.Json での同等機能 |
---|---|
既定での大文字と小文字の区別のない逆シリアル化 | ✔️ PropertyNameCaseInsensitive グローバル設定 |
キャメルケースのプロパティ名 | ✔️ PropertyNamingPolicy グローバル設定 |
最小限の文字のエスケープ | ✔️ 厳密な文字エスケープ、構成可能 |
NullValueHandling.Ignore グローバル設定 |
✔️ DefaultIgnoreCondition グローバル オプション |
コメントを許可する | ✔️ ReadCommentHandling グローバル設定 |
末尾のコンマを許可する | ✔️ AllowTrailingCommas グローバル設定 |
カスタム コンバーターの登録 | ✔️ 優先順位の順序が異なる |
既定の最大深度は 64、構成可能 | ✔️ 既定の最大深度は 64、構成可能 |
PreserveReferencesHandling グローバル設定 |
✔️ ReferenceHandling グローバル設定 |
引用符で囲まれた数値をシリアル化または逆シリアル化する | ✔️ NumberHandling グローバル設定、[JsonNumberHandling] 属性 |
不変のクラスと構造体への逆シリアル化 | ✔️ JsonConstructor、C# 9 のレコード |
フィールドのサポート | ✔️ IncludeFields グローバル設定、[JsonInclude] 属性 |
DefaultValueHandling グローバル設定 |
✔️ DefaultIgnoreCondition グローバル設定 |
[JsonProperty] での NullValueHandling の設定 |
✔️ JsonIgnore 属性 |
[JsonProperty] での DefaultValueHandling の設定 |
✔️ JsonIgnore 属性 |
文字列以外のキーを含む Dictionary を逆シリアル化する |
✔️ Supported |
非パブリック プロパティのセッターとゲッターのサポート | ✔️ JsonInclude 属性 |
[JsonConstructor] 属性 |
✔️ [JsonConstructor] 属性 |
ReferenceLoopHandling グローバル設定 |
✔️ ReferenceHandling グローバル設定 |
コールバック | ✔️ コールバック |
NaN、Infinity、-Infinity | ✔️ Supported |
文字列列挙型の値を逆シリアル化する | ✔️ 文字列列挙型の値を逆シリアル化する |
さまざまな型のサポート | ⚠ 一部の型にはカスタム コンバーターが必要 |
ポリモーフィックなシリアル化 | ⚠ 非サポート、回避策、サンプル |
ポリモーフィックな逆シリアル化 | ⚠ 非サポート、回避策、サンプル |
推論された型を object のプロパティに逆シリアル化する |
⚠ 非サポート、回避策、サンプル |
JSON の null リテラルを null 非許容値の型に逆シリアル化する |
⚠ 非サポート、回避策、サンプル |
[JsonProperty] 属性での Required の設定 |
⚠ 非サポート、回避策、サンプル |
プロパティを無視するための DefaultContractResolver |
⚠ 非サポート、回避策、サンプル |
DateTimeZoneHandling 、DateFormatString の設定 |
⚠ 非サポート、回避策、サンプル |
JsonConvert.PopulateObject メソッド |
⚠ 非サポート、回避策 |
ObjectCreationHandling グローバル設定 |
⚠ 非サポート、回避策 |
セッターなしでコレクションに追加する | ⚠ 非サポート、回避策 |
スネークケースのプロパティ名 | ⚠ 非サポート、回避策 |
JsonObjectAttribute |
⚠ 非サポート、回避策 |
System.Runtime.Serialization 属性のサポート |
❌サポートされていません |
MissingMemberHandling グローバル設定 |
❌サポートされていません |
引用符なしのプロパティ名を許可する | ❌デザインでサポートされていません |
文字列値を囲む単一引用符を許可する | ❌デザインでサポートされていません |
文字列のプロパティに対して文字列ではない JSON 値を許可する | ❌デザインでサポートされていません |
TypeNameHandling.All グローバル設定 |
❌デザインでサポートされていません |
JsonPath クエリのサポート |
❌サポートされていません |
構成可能な制限 | ❌サポートされていません |
これは Newtonsoft.Json
機能の包括的なリストではありません。 この一覧には、GitHub の問題または StackOverflow の投稿でリクエストされたシナリオの多くが含まれています。 ここに一覧表示されたシナリオのうち、現在サンプル コードがないシナリオの 1 つに回避策を実装する場合、およびご自分の解決策を共有する場合は、このページの下部にある [フィードバック] セクションで [このページ] を選択してください。 これにより、問題がこのドキュメントの GitHub リポジトリに作成され、このページの [フィードバック] セクションにも記載されます。
既定の動作においての相違点
既定では System.Text.Json は厳格であり、確定的な動作を重視して、呼び出し元のために推測や解釈は行われません。 このライブラリは、パフォーマンスとセキュリティを確保するために意図的にこのように設計されています。 Newtonsoft.Json
は既定で柔軟性を持っています。 設計上のこの基本的な違いが、既定の動作における次のような固有の相違点の多くで、その背景にあります。
大文字と小文字の区別のない逆シリアル化
逆シリアル化中、Newtonsoft.Json
では、大文字と小文字の区別のないプロパティ名の照合が既定で行われます。 System.Text.Json の既定では大文字と小文字が区別されます。完全一致が行われるため、これによってパフォーマンスが向上します。 大文字と小文字の区別のない照合の実行方法については、「大文字と小文字を区別しないプロパティ照合」を参照してください。
ASP.NET Core を使用して System.Text.Json
を間接的に使用している場合、Newtonsoft.Json
のような動作を得るために何かをする必要はありません。 ASP.NET Core では、System.Text.Json
を使用するときに、Camel 形式のプロパティ名および大文字と小文字を区別しない照合のための設定が指定されます。
ASP.NET Core を使用すると、引用符で囲まれた数値を既定で逆シリアル化することもできます。
最小限の文字のエスケープ
シリアル化中、Newtonsoft.Json
では文字をエスケープしないままにすることが比較的許容されています。 つまり、xxxx
が文字のコード ポイントである場合、その文字が \uxxxx
には置き換えられません。 文字がエスケープされる場合、その文字の前に \
が出力されます (たとえば、"
は \"
になります)。 System.Text.Json の場合、既定でより多くの文字がエスケープされ、クロスサイト スクリプティング (XSS) や情報漏えいの攻撃に対する多層防御保護が実現します。そのために 6 文字のシーケンスが使用されます。 System.Text.Json
では、既定で ASCII 以外の文字がすべてエスケープされるため、Newtonsoft.Json
で StringEscapeHandling.EscapeNonAscii
を使用している場合は、何もする必要はありません。 また、System.Text.Json
では、既定で HTML に影響する文字もエスケープされます。 System.Text.Json
の既定の動作をオーバーライドする方法については、「System.Text.Json
」を参照してください。
コメント
逆シリアル化中、Newtonsoft.Json
では既定で JSON 内のコメントは無視されます。 System.Text.Json の既定では、コメントに対して例外がスローされます。System.Text.Json 仕様にそれが含まれていないためです。 コメントを許可する方法については、「コメントと末尾のコンマを許可する」を参照してください。
末尾のコンマ
逆シリアル化中、Newtonsoft.Json
では既定で末尾のコンマは無視されます。 また、複数の末尾のコンマ (たとえば、[{"Color":"Red"},{"Color":"Green"},,]
) も無視されます。 System.Text.Json の既定では、末尾のコンマに対して例外がスローされます。System.Text.Json 仕様でそれが許可されていないためです。 System.Text.Json
で受け入れられるようにする方法については、「System.Text.Json
」を参照してください。 複数の末尾のコンマが許可されるようにする方法はありません。
コンバーターの登録の優先順位
Newtonsoft.Json
でのカスタム コンバーターの登録の優先順位は次のとおりです。
- プロパティの属性
- 型の属性
- Converters コレクション
この順序は、Converters
コレクション内のカスタム コンバーターが、型レベルの属性を適用して登録されたコンバーターによってオーバーライドされることを意味します。 これらの登録はどちらも、プロパティ レベルの属性によってオーバーライドされます。
System.Text.Json でのカスタム コンバーターの登録の優先順位は異なります。
- プロパティの属性
- Converters コレクション
- 型の属性
ここでの違いは、Converters
コレクション内のカスタム コンバーターによって型レベルの属性がオーバーライドされる点です。 この優先順位の背後にある意図は、実行時の変更によって設計時の選択がオーバーライドされるようにすることです。 優先順位を変更する方法はありません。
カスタム コンバーターの登録の詳細については、「カスタム コンバーターを登録する」を参照してください。
最大の深さ
Newtonsoft.Json
の最新バージョンでは、既定で最大深度制限は 64 です。 System.Text.Json の既定の制限も 64 であり、JsonSerializerOptions.MaxDepth を設定して構成できます。
ASP.NET Core を使用し、System.Text.Json
を間接的に使用している場合、深さ上限の既定値は 32 です。 この既定値はモデル バインドの場合と同じであり、JsonOptions クラスで設定されます。
JSON 文字列 (プロパティ名と文字列値)
逆シリアル化中、Newtonsoft.Json
では、二重引用符か単一引用符で囲まれた、または引用符なしのプロパティ名が受け取入れられます。 文字列値は、二重引用符または単一引用符で囲まれたものが受け入れられます。 たとえば、Newtonsoft.Json
では次の JSON が受け入れられます。
{
"name1": "value",
'name2': "value",
name3: 'value'
}
System.Text.Json
では、二重引用符で囲まれたプロパティ名と文字列値のみが受け入れられます。この形式が System.Text.Json
仕様で要求されており、有効な JSON と見なされる唯一の形式であるためです。
値を単一引用符で囲むと、次のメッセージと共に JsonException が発生します。
''' is an invalid start of a value.
文字列プロパティに対する文字列以外の値
Newtonsoft.Json
では、文字列型のプロパティへの逆シリアル化の場合、数値やリテラル true
と false
など、文字列以外の値が受け入れられます。 Newtonsoft.Json
で次のクラスへの逆シリアル化が正常に行われてる JSON の例を、以下に示します。
{
"String1": 1,
"String2": true,
"String3": false
}
public class ExampleClass
{
public string String1 { get; set; }
public string String2 { get; set; }
public string String3 { get; set; }
}
System.Text.Json
では、文字列以外の値は文字列プロパティに逆シリアル化されません。 文字列フィールドに対して文字列以外の値を受け取ると、次のメッセージと共に JsonException が発生します。
The JSON value could not be converted to System.String.
JsonSerializer を使用するシナリオ
次のシナリオの一部は、組み込み機能ではサポートされていませんが、回避策を適用できます。 回避策とはカスタム コンバーターのことですが、これによって Newtonsoft.Json
の機能との完全なパリティが得られるとは限りません。 これらの一部については、サンプル コードが例として提供されます。 Newtonsoft.Json
のこれらの機能を利用する必要がある場合、移行するには、.NET オブジェクト モデルに対する変更やその他のコード変更が必要になります。
次のシナリオの一部では、回避策は実用的でないか不可能です。 Newtonsoft.Json
のこれらの機能を利用する必要がある場合、移行を可能にするには大幅な変更が必要です。
引用符で囲まれた数値を許可または記述する
Newtonsoft.Json
では、JSON 文字列によって表された (引用符で囲まれた) 数値をシリアル化または逆シリアル化できます。 たとえば、{"DegreesCelsius":23}
ではなく {"DegreesCelsius":"23"}
を受け入れることができます。 System.Text.Json でその動作を有効にするには、JsonSerializerOptions.NumberHandling を WriteAsString または AllowReadingFromString に設定するか、System.Text.Json 属性を使用します。
ASP.NET Core を使用して System.Text.Json
を間接的に使用している場合、Newtonsoft.Json
のような動作を得るために何かをする必要はありません。 System.Text.Json
が使用されていて、Web の既定値で引用符で囲まれた数値が許可されている場合、ASP.NET Core により Web の既定値が指定されます。
詳細については、「引用符で囲まれた数値を許可または記述する」を参照してください。
逆シリアル化のときに使用するコンストラクターを指定する
Newtonsoft.Json
の [JsonConstructor]
属性を使用すると、POCO への逆シリアル化時に呼び出すコンストラクターを指定できます。
System.Text.Json
には、System.Text.Json
属性もあります。 詳細については、「不変の型とレコード」を参照してください。
プロパティを条件付きで無視する
Newtonsoft.Json
には、シリアル化または逆シリアル化時にプロパティを条件付きで無視する方法がいくつか用意されています。
DefaultContractResolver
を使用すると、任意の条件に基づいて含めたり無視したりするプロパティを選択できます。JsonSerializerSettings
のNullValueHandling
とDefaultValueHandling
の設定を使用すると、null 値または既定値のすべてのプロパティを無視することを指定できます。[JsonProperty]
属性のNullValueHandling
とDefaultValueHandling
の設定を使用すると、null または既定値に設定されている場合に無視する個々のプロパティを指定できます。
System.Text.Json には、シリアル化中にプロパティまたはフィールドを無視するために次の方法が用意されています。
- プロパティで [JsonIgnore] 属性を使用すると、シリアル化中にそのプロパティが JSON から除外されます。
- IgnoreReadOnlyProperties グローバル オプションを使用すると、すべての読み取り専用プロパティを無視できます。
- フィールドを含める場合は、JsonSerializerOptions.IgnoreReadOnlyFields グローバル オプションを使用すると、すべての読み取り専用フィールドを無視できます。
DefaultIgnoreCondition
グローバル オプションを使用すると、DefaultIgnoreCondition
こと、またはnull 値が設定されているすべての参照型プロパティを無視することができます。
さらに、.NET 7 以降のバージョンでは、任意の条件に基づいてプロパティを無視するように JSON コントラクトをカスタマイズできます。 詳細については、「カスタム コントラクト」を参照してください。
これらのオプションでは、実行時に評価された任意の条件に基づいて選択されたプロパティを無視することはできません。
パブリックおよび非パブリック フィールド
Newtonsoft.Json
では、フィールドおよびプロパティをシリアル化および逆シリアル化できます。
System.Text.Json では、シリアル化または逆シリアル化のときにフィールドを含めるには、JsonSerializerOptions.IncludeFields グローバル設定または System.Text.Json 属性を使用します。 例については、「フィールドを含める」を参照してください。
オブジェクト参照を保持してループを処理する
既定では、Newtonsoft.Json
では値によってシリアル化します。 たとえば、オブジェクトに同じ Person
オブジェクトへの参照を含む 2 つのプロパティが含まれている場合、その Person
オブジェクトのプロパティの値は JSON 内で複製されます。
Newtonsoft.Json
には、JsonSerializerSettings
に、参照によってシリアル化できるようにする PreserveReferencesHandling
設定があります。
- 最初の
Person
オブジェクト用に作成された JSON に識別子メタデータが追加されます。 - 2番目の
Person
オブジェクト用に作成された JSON には、プロパティ値ではなく、その識別子への参照が含まれます。
Newtonsoft.Json
には、例外をスローするのではなく循環参照を無視できるようにする ReferenceLoopHandling
設定もあります。
System.Text.Json で参照を保持し、循環参照を処理するには、JsonSerializerOptions.ReferenceHandler を Preserve に設定します。 ReferenceHandler.Preserve
設定は、Newtonsoft.Json
での PreserveReferencesHandling
= PreserveReferencesHandling.All
に相当します。
ReferenceHandler.IgnoreCycles
オプションは、Newtonsoft.JsonReferenceLoopHandling.Ignore
と同様に動作します。 1 つの違いは、System.Text.Json の実装では、参照ループが、オブジェクト参照を無視するのではなく、null
JSON トークンに置き換えられている点です。 詳細については、「循環参照を無視する」を参照してください。
Newtonsoft.JsonNewtonsoft.Json のように、シリアル化と逆シリアル化で参照を維持する動作が、System.Text.Json.Serialization.ReferenceResolver クラスによって定義されます。 カスタム動作を指定するには、派生クラスを作成します。 例については、GuidReferenceResolver に関するページを参照してください。
一部の関連する Newtonsoft.Json
機能はサポートされていません:
詳細については、「参照を保持し、循環参照を処理する」を参照してください。
文字列以外のキーを含むディクショナリ
Newtonsoft.Json
と System.Text.Json
のどちらでも、Dictionary<TKey, TValue>
型のコレクションがサポートされています。 ただし、System.Text.Json
では、TKey
はカスタムの型ではなく、プリミティブ型にする必要があります。 詳細については、サポートされているキーの型に関するページをご覧ください。
注意事項
TKey
が string
以外のものとして型指定される Dictionary<TKey, TValue>
に逆シリアル化すると、それを使用するアプリケーションでセキュリティに脆弱性が生じるおそれがあります。 詳細については、「dotnet/runtime#4761」を参照してください。
組み込みサポートのない型
System.Text.Json には、次の型に対する組み込みサポートはありません。
- DataTable および関連する型 (詳細については、「DataTable」を参照してください)
- ExpandoObject
- TimeZoneInfo
- BigInteger
- DBNull
- Type
- ValueTuple およびそれに関連付けられているジェネリック型
カスタム コンバーターは、組み込みサポートのない型に対して実装できます。
ポリモーフィックなシリアル化
Newtonsoft.Json
では、ポリモーフィックなシリアル化が自動的に行われます。 .NET 7 以降、System.Text.Json では、JsonDerivedTypeAttribute 属性を使用したポリモーフィックなシリアル化がサポートされています。 詳細については、「派生クラスのプロパティをシリアル化する」を参照してください。
ポリモーフィックな逆シリアル化
Newtonsoft.Json
には、シリアル化中に型名のメタデータを JSON に追加する TypeNameHandling
設定があります。 これは、逆シリアル化中にそのメタデータを使用して、ポリモーフィックな逆シリアル化を行います。 .NET 7 以降では、ポリモーフィックな逆シリアル化を実行するために、System.Text.Json は型判別子情報に依存します。 このメタデータは JSON で出力され、逆シリアル化中に使用され、基本型と派生型のどちらに逆シリアル化するかを判断します。 詳細については、「派生クラスのプロパティをシリアル化する」を参照してください。
以前の .NET バージョンでポリモーフィックな逆シリアル化をサポートするには、「カスタム コンバーターを記述する方法」の例のようなコンバーターを作成します。
文字列列挙型の値を逆シリアル化する
既定では、文字列列挙型の値の逆シリアル化は System.Text.Json ではサポートされませんが、Newtonsoft.Json
ではサポートされます。 たとえば、次のコードでは JsonException がスローされます。
string json = "{ \"Text\": \"Hello\", \"Enum\": \"Two\" }";
var _ = JsonSerializer.Deserialize<MyObj>(json); // Throws exception.
class MyObj
{
public string Text { get; set; } = "";
public MyEnum Enum { get; set; }
}
enum MyEnum
{
One,
Two,
Three
}
ただし、JsonStringEnumConverter コンバーターを使用して文字列列挙型の値の逆シリアル化を有効にすることができます。 詳細については、「文字列としての列挙型」を参照してください。
オブジェクト プロパティの逆シリアル化
Newtonsoft.Json
では、Object への逆シリアル化中に以下が行われます。
- JSON ペイロード内のプリミティブ値 (
null
以外) の型を推測し、格納されているstring
、long
、double
、boolean
、またはDateTime
をボックス化されたオブジェクトとして返します。 "プリミティブ値" は、JSON の数値、文字列、true
、false
、null
などの 1 つの JSON 値です。 - JSON ペイロード内の複合値の
JObject
またはJArray
を返します。 "複合値" は、中かっこ ({}
) 内の JSON のキーと値のペアのコレクション、または角かっこ ([]
) 内の値のリストです。 中かっこまたは角かっこ内のプロパティと値には、追加のプロパティまたは値を含めることができます。 - ペイロードに
null
JSON リテラルが含まれている場合は、null 参照を返します。
System.Text.Json では、Object への逆シリアル化中には常に、プリミティブと複合の両方の値に対してボックス化された JsonElement
が格納されます。例えば、以下のようなものです。
object
プロパティ。object
ディクショナリ値。object
配列値。- ルート
object
。
ただし、System.Text.Json
では null
が Newtonsoft.Json
と同じ方法で処理され、ペイロードに null
JSON リテラルが含まれている場合は null 参照が返されます。
object
プロパティに型の推定を実装するには、object
に関する記事の例にあるようなコンバーターを作成します。
null を null 非許容型に逆シリアル化する
Newtonsoft.Json
では、次のシナリオでは例外がスローされません。
NullValueHandling
がIgnore
に設定されている。さらに- 逆シリアル化中に、JSON の null 非許容値型に null 値が含まれている。
System.Text.Json では、同じシナリオで例外がスローされます。 (System.Text.Json
での対応する null 処理設定は JsonSerializerOptions.IgnoreNullValues = true
です。)
ターゲット型を所有している場合、最適な回避策は、問題のプロパティを null 許容にすることです (たとえば、int
を int?
に変更します)。
もう 1 つの回避策として、DateTimeOffset
型に対する null 値を処理する次の例のように、型のコンバーターを作成する方法があります。
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class DateTimeOffsetNullHandlingConverter : JsonConverter<DateTimeOffset>
{
public override DateTimeOffset Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
reader.TokenType == JsonTokenType.Null
? default
: reader.GetDateTimeOffset();
public override void Write(
Utf8JsonWriter writer,
DateTimeOffset dateTimeValue,
JsonSerializerOptions options) =>
writer.WriteStringValue(dateTimeValue);
}
}
このカスタム コンバーターを登録するには、プロパティで属性を使用するか、Converters コレクションにコンバーター を追加します。
注: 上記のコンバーターでは、既定値を指定する POCO に対して Newtonsoft.Json
が処理する場合とは異なる方法で null 値が処理されます。 たとえば、次のコードがターゲット オブジェクトを表しているとします。
public class WeatherForecastWithDefault
{
public WeatherForecastWithDefault()
{
Date = DateTimeOffset.Parse("2001-01-01");
Summary = "No summary";
}
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
}
さらに、上記のコンバーターを使用して、次の JSON が逆シリアル化されるとします。
{
"Date": null,
"TemperatureCelsius": 25,
"Summary": null
}
逆シリアル化が行われた後、Date
プロパティには 1/1/0001 (default(DateTimeOffset)
) が設定されます。つまり、コンストラクターで設定された値が上書きされます。 同じ POCO と JSON を使用する場合、Newtonsoft.Json
の逆シリアル化では Date
プロパティに 1/1/2001 が設定されたままになります。
不変のクラスと構造体への逆シリアル化
Newtonsoft.Json
では、パラメーターを持つコンストラクターを使用できるため、不変のクラスと構造体に逆シリアル化できます。
System.Text.Json では、パラメーター化されたコンストラクターの使用を指定するには System.Text.Json 属性を使用します。 C# 9 のレコードも不変であり、逆シリアル化ターゲットとしてサポートされています。 詳細については、「不変の型とレコード」を参照してください。
必須プロパティ
Newtonsoft.Json
では、[JsonProperty]
属性に Required
を設定して、プロパティが必須であることを指定します。 必須とマーク付けされたプロパティに対して JSON で値が取得されない場合、Newtonsoft.Json
で例外がスローされます。
.NET 7 以降では、必須プロパティで C# required
修飾子または JsonRequiredAttribute 属性を使用できます。 JSON ペイロードにマークされたプロパティの値が含まれていない場合、System.Text.Json では例外がスローされます。 詳細については、「必須プロパティ」を参照してください。
System.Text.Json では、ターゲット型のいずれかのプロパティに対して値が取得されない場合でも、例外はスローされません。 たとえば、WeatherForecast
クラスがあるとします。
public class WeatherForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
次の JSON はエラーなしで逆シリアル化されます。
{
"TemperatureCelsius": 25,
"Summary": "Hot"
}
JSON に Date
プロパティがない場合に逆シリアル化を失敗させるには、次のいずれかのオプションを選択します。
- System.Text.Json パッケージ の .NET 7 以降のバージョンを使用し、
required
修飾子 (C# 11 以降で使用可能) または JsonRequiredAttribute 属性をプロパティに追加します。 - カスタム コンバーターを実装します。
OnDeserialized
コールバック (.NET 6 以降) を実装します。
次のサンプル コンバーター コードでは、逆シリアル化の完了後に Date
プロパティが設定されていない場合は例外がスローされます。
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class WeatherForecastRequiredPropertyConverter : JsonConverter<WeatherForecast>
{
public override WeatherForecast Read(
ref Utf8JsonReader reader,
Type type,
JsonSerializerOptions options)
{
// Don't pass in options when recursively calling Deserialize.
WeatherForecast forecast = JsonSerializer.Deserialize<WeatherForecast>(ref reader)!;
// Check for required fields set by values in JSON
return forecast!.Date == default
? throw new JsonException("Required property not received in the JSON")
: forecast;
}
public override void Write(
Utf8JsonWriter writer,
WeatherForecast forecast, JsonSerializerOptions options)
{
// Don't pass in options when recursively calling Serialize.
JsonSerializer.Serialize(writer, forecast);
}
}
}
このカスタム コンバーターを登録するには、JsonSerializerOptions.Converters コレクションにコンバーターを追加します。
コンバーターを再帰的に呼び出すこのパターンでは、属性を使用するのではなく、JsonSerializerOptions を使用してコンバーターを登録する必要があります。 属性を使用してこのコンバーターを登録する場合、カスタム コンバーターによってそれ自体が再帰的に呼び出されます。 その結果、スタック オーバーフロー例外で終了する無限ループが発生します。
オプション オブジェクトを使用してコンバーターを登録する場合は、Serialize または Deserialize を再帰的に呼び出すときにオプション オブジェクトで渡さないようにして、無限ループを回避します。 オプション オブジェクトには、Converters コレクションが含まれています。 それを Serialize
または Deserialize
に渡すと、カスタム コンバーターはそれ自体を呼び出し、無限ループが形成され、結果的にスタック オーバーフロー例外が発生します。 既定のオプションを使用できない場合は、必要な設定を使用してオプションの新しいインスタンスを作成します。 この方法では、新しい各インスタンスが個別にキャッシュされるため、速度が遅くなります。
変換されるクラスで JsonConverterAttribute
の登録を使用できる代替パターンがあります。 この方法では、変換されるクラスから派生したクラスで、コンバーター コードによって Serialize
または Deserialize
が呼び出されます。 この派生クラスには、JsonConverterAttribute
が適用されていません。 この代替の例を次に示します。
WeatherForecastWithRequiredPropertyConverterAttribute
は、逆シリアル化されるクラスであり、JsonConverterAttribute
が適用されています。WeatherForecastWithoutRequiredPropertyConverterAttribute
は、コンバーター属性を持たない派生クラスです。- 無限ループを回避するために、コンバーターのコードによって、
WeatherForecastWithoutRequiredPropertyConverterAttribute
でSerialize
とDeserialize
が呼び出されます。 追加のオブジェクトのインスタンス化とプロパティ値のコピーによって、このシリアル化の方法にはパフォーマンス コストが発生します。
次に WeatherForecast*
の種類を示します。
[JsonConverter(typeof(WeatherForecastRequiredPropertyConverterForAttributeRegistration))]
public class WeatherForecastWithRequiredPropertyConverterAttribute
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
public class WeatherForecastWithoutRequiredPropertyConverterAttribute :
WeatherForecastWithRequiredPropertyConverterAttribute
{
}
コンバーターを次に示します。
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class WeatherForecastRequiredPropertyConverterForAttributeRegistration :
JsonConverter<WeatherForecastWithRequiredPropertyConverterAttribute>
{
public override WeatherForecastWithRequiredPropertyConverterAttribute Read(
ref Utf8JsonReader reader,
Type type,
JsonSerializerOptions options)
{
// OK to pass in options when recursively calling Deserialize.
WeatherForecastWithRequiredPropertyConverterAttribute forecast =
JsonSerializer.Deserialize<WeatherForecastWithoutRequiredPropertyConverterAttribute>(
ref reader,
options)!;
// Check for required fields set by values in JSON.
return forecast!.Date == default
? throw new JsonException("Required property not received in the JSON")
: forecast;
}
public override void Write(
Utf8JsonWriter writer,
WeatherForecastWithRequiredPropertyConverterAttribute forecast,
JsonSerializerOptions options)
{
var weatherForecastWithoutConverterAttributeOnClass =
new WeatherForecastWithoutRequiredPropertyConverterAttribute
{
Date = forecast.Date,
TemperatureCelsius = forecast.TemperatureCelsius,
Summary = forecast.Summary
};
// OK to pass in options when recursively calling Serialize.
JsonSerializer.Serialize(
writer,
weatherForecastWithoutConverterAttributeOnClass,
options);
}
}
}
属性 ([JsonIgnore] など) または別のオプション (カスタム エンコーダーなど) を処理する必要がある場合、必須プロパティのコンバーターには追加のロジックが必要です。 また、例のコードでは、既定値がコンストラクター内で設定されているプロパティは処理されません。 さらに、この方法では次のシナリオの違いは識別されません。
- プロパティが JSON から欠落している。
- null 非許容型のプロパティが JSON に存在するが、値がその型の既定である (たとえば、
int
ではゼロ)。 - null 許容値型のプロパティが JSON に存在するが、値が null である。
Note
ASP.NET Core コントローラーから System.Text.Json を使用している場合は、System.Text.Json コンバーターを実装するのでなく、モデル クラスのプロパティに対して [Required]
属性を使用できる場合があります。
日付形式を指定する
Newtonsoft.Json
には、DateTime
および DateTimeOffset
型のプロパティをどのようにシリアル化および逆シリアル化するかを制御する方法がいくつか用意されています。
DateTimeZoneHandling
設定を使用すると、すべてのDateTime
値を UTC 日付としてシリアル化できます。DateFormatString
設定とDateTime
コンバーターを使用すると、日付文字列の形式をカスタマイズできます。
System.Text.Json は、RFC 3339 プロファイルを含む ISO 8601-1:2019 をサポートしています。 この形式は広く採用されており、明確で、正確にラウンドトリップを行います。 他の形式を使用するには、カスタム コンバーターを作成します。 たとえば、次のコンバーターを使用すると、Unix エポックのタイム ゾーン オフセットがある形式とない形式 (/Date(1590863400000-0700)/
や /Date(1590863400000)/
などの値) を使用する JSON がシリアル化および逆シリアル化されます。
sealed class UnixEpochDateTimeOffsetConverter : JsonConverter<DateTimeOffset>
{
static readonly DateTimeOffset s_epoch = new(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)([+-])(\\d{2})(\\d{2})\\)/$", RegexOptions.CultureInvariant);
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string formatted = reader.GetString()!;
Match match = s_regex.Match(formatted);
if (
!match.Success
|| !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime)
|| !int.TryParse(match.Groups[3].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int hours)
|| !int.TryParse(match.Groups[4].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int minutes))
{
throw new JsonException();
}
int sign = match.Groups[2].Value[0] == '+' ? 1 : -1;
TimeSpan utcOffset = new(hours * sign, minutes * sign, 0);
return s_epoch.AddMilliseconds(unixTime).ToOffset(utcOffset);
}
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options)
{
long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);
TimeSpan utcOffset = value.Offset;
string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/");
writer.WriteStringValue(formatted);
}
}
sealed class UnixEpochDateTimeConverter : JsonConverter<DateTime>
{
static readonly DateTime s_epoch = new(1970, 1, 1, 0, 0, 0);
static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)\\)/$", RegexOptions.CultureInvariant);
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string formatted = reader.GetString()!;
Match match = s_regex.Match(formatted);
if (
!match.Success
|| !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime))
{
throw new JsonException();
}
return s_epoch.AddMilliseconds(unixTime);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);
string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime})/");
writer.WriteStringValue(formatted);
}
}
詳細については、「System.Text.Json での DateTime と DateTimeOffset のサポート」を参照してください。
コールバック
Newtonsoft.Json
では、シリアル化または逆シリアル化プロセスの複数の時点でカスタム コードを実行できます。
- OnDeserializing (オブジェクトの逆シリアル化の開始時点)
- OnDeserialized (オブジェクトの逆シリアル化の完了時点)
- OnSerializing (オブジェクトのシリアル化の開始時点)
- OnSerialized (オブジェクトのシリアル化の完了時点)
System.Text.Json では、シリアル化のときも逆シリアル化のときも同じ通知を公開します。 それらを使用するには、System.Text.Json.Serialization 名前空間から次のインターフェイスを 1 つまたは複数実装します。
次に示すのは、シリアル化と逆シリアル化の開始と終了で null プロパティがないか確認し、メッセージを書き込む例です。
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Callbacks
{
public class WeatherForecast :
IJsonOnDeserializing, IJsonOnDeserialized,
IJsonOnSerializing, IJsonOnSerialized
{
public DateTime Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
void IJsonOnDeserializing.OnDeserializing() => Console.WriteLine("\nBegin deserializing");
void IJsonOnDeserialized.OnDeserialized()
{
Validate();
Console.WriteLine("Finished deserializing");
}
void IJsonOnSerializing.OnSerializing()
{
Console.WriteLine("Begin serializing");
Validate();
}
void IJsonOnSerialized.OnSerialized() => Console.WriteLine("Finished serializing");
private void Validate()
{
if (Summary is null)
{
Console.WriteLine("The 'Summary' property is 'null'.");
}
}
}
public class Program
{
public static void Main()
{
var weatherForecast = new WeatherForecast
{
Date = DateTime.Parse("2019-08-01"),
TemperatureCelsius = 25,
};
string jsonString = JsonSerializer.Serialize(weatherForecast);
Console.WriteLine(jsonString);
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString);
Console.WriteLine($"Date={weatherForecast?.Date}");
Console.WriteLine($"TemperatureCelsius={weatherForecast?.TemperatureCelsius}");
Console.WriteLine($"Summary={weatherForecast?.Summary}");
}
}
}
// output:
//Begin serializing
//The 'Summary' property is 'null'.
//Finished serializing
//{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":null}
//Begin deserializing
//The 'Summary' property is 'null'.
//Finished deserializing
//Date=8/1/2019 12:00:00 AM
//TemperatureCelsius = 25
//Summary=
OnDeserializing
コードでは、新しい POCO インスタンスにアクセスできません。 逆シリアル化の開始時に新しい POCO インスタンスを操作するには、そのコードを POCO コンストラクターに挿入します。
非パブリック プロパティのセッターとゲッター
Newtonsoft.Json
では、JsonProperty
属性を通じて、プライベートおよび内部プロパティのセッターとゲッターを使用できます。
System.Text.Json では、System.Text.Json 属性を通じて、プライベートおよび内部プロパティのセッターとゲッターがサポートされます。 サンプル コードについては、「パブリックでないプロパティ アクセサー」を参照してください。
既存のオブジェクトの設定
Newtonsoft.Json
の JsonConvert.PopulateObject
メソッドでは、新しいインスタンスを作成するのではなく、クラスの既存のインスタンスに JSON ドキュメントが逆シリアル化されます。 System.Text.Json では常に、既定のパラメーターなしのパブリック コンストラクターを使用して、ターゲット型の新しいインスタンスが作成されます。 カスタム コンバーターによって、既存のインスタンスに逆シリアル化できます。
プロパティを置き換えるのではなく再利用する
.NET 8 以降では、System.Text.Json を使用すると、初期化されたプロパティを置き換える代わりに再利用できます。 動作にはいくつかの違いがあり、API の提案に関するページで確認できます。
詳細については、「初期化されたプロパティの設定」を参照してください。
Newtonsoft.Json
の ObjectCreationHandling
設定を使用すると、逆シリアル化中にプロパティ内のオブジェクトを置き換えるのではなく、再利用することを指定できます。 System.Text.Json では常に、プロパティ内のオブジェクトが置き換えられます。 カスタム コンバーターはこの機能を提供でき、設定機能を提供する .NET 8 にアップグレードすることもできます。
セッターを持たないプロパティを設定する
.NET 8 以降では、System.Text.Json を使用すると、セッターを持たないプロパティを含むプロパティの設定を行うことができます。 詳細については、「初期化されたプロパティの設定」を参照してください。
逆シリアル化中、Newtonsoft.Json
ではプロパティにセッターがない場合でも、オブジェクトがコレクションに追加されます。 System.Text.Json では、セッターのないプロパティは無視されます。 カスタム コンバーターはこの機能を提供でき、読み取り専用プロパティを提供できる .NET 8 にアップグレードすることもできます。
スネーク ケースの名前付けポリシー
System.Text.Json には、スネーク ケースの組み込みの名前付けポリシーが含まれています。 ただし、一部の入力では Newtonsoft.Json
との動作の違いがあります。 次の表は、JsonNamingPolicy.SnakeCaseLower ポリシーを使用して入力を変換するときのこれらの違いをいくつか示しています。
入力 | Newtonsoft.Json の結果 | System.Text.Json の結果 |
---|---|---|
"AB1" | "a_b1" | "ab1" |
"SHA512Managed" | "sh_a512_managed" | "sha512_managed" |
"abc123DEF456" | "abc123_de_f456" | "abc123_def456" |
"KEBAB-CASE" | "keba_b-_case" | "kebab-case" |
System.Text.Json の唯一の組み込みプロパティ名前付けポリシーはキャメル ケース用です。 Newtonsoft.Json
では、プロパティ名をスネーク ケースに変換できます。 カスタム名前付けポリシーでは、この機能を提供したり、組み込みのスネーク ケースの名前付けポリシーを含む .NET 8 以降にアップグレードしたりできます。
System.Runtime.Serialization 属性
DataContractAttribute、DataMemberAttribute などの System.Runtime.Serialization 属性、IgnoreDataMemberAttribute ではデータ コントラクトを定義できます。 データ コントラクトは、サービスとクライアントの間の正式な取り決めであり、交換されるデータが抽象的に記述されています。 データ コントラクトは、交換のためにシリアル化されるプロパティを正確に定義します。
System.Text.Json には、これらの属性の組み込みサポートがありません。 ただし、.NET 7 以降では、 カスタム型リゾルバー を使用してサポートを追加できます。 サンプルについては、「ZCS.DataContractResolver」を参照してください 。
8 進数
Newtonsoft.Json
では、先頭にゼロを持つ数値は 8 進数として扱われます。 System.Text.Json では先頭のゼロは許容されません。System.Text.Json 仕様で許可されていないためです。
不足しているすべてのメンバーを処理します
逆シリアル化されている JSON にターゲット型に存在しないプロパティが含まれている場合は、Newtonsoft.Json
は例外をスローするようにを構成できます。 System.Text.Json の既定では、[JsonExtensionData] 属性を使用する場合を除き、JSON 内の余分なプロパティは無視されます。
.NET 8 以降のバージョンでは、次のいずれかの方法を使用して、マップされていない JSON プロパティをスキップするか禁止するかを設定できます。
- 逆シリアル化先の型に JsonUnmappedMemberHandlingAttribute 属性を適用します。
- ユーザー設定をグローバルに設定するには、JsonSerializerOptions.UnmappedMemberHandling プロパティを設定します。 または、ソース生成の場合は、JsonSourceGenerationOptionsAttribute.UnmappedMemberHandling プロパティを設定し、JsonSerializerContext クラスに属性を適用します。
- JsonTypeInfo.UnmappedMemberHandling プロパティをカスタマイズします。
JsonObjectAttribute
Newtonsoft.Json
には 属性 JsonObjectAttribute
があります。この属性は、シリアル化されるメンバー、null
値の処理方法、およびすべてのメンバーが必要かどうかを制御するために、型レベル で適用できます。 System.Text.Json には、型に適用できる同等の属性がありません。 null
値の処理などの一部の動作では、グローバル JsonSerializerOptions で同じ動作を構成することも、各プロパティで個別に構成することもできます。
Newtonsoft.Json.JsonObjectAttribute
を使用 してすべての null
プロパティを無視するように指定する次の例を考えてみましょう:
[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
public class Person { ... }
System.Text.Json では、 すべての型とプロパティの動作を設定できます:
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
string json = JsonSerializer.Serialize<Person>(person, options);
または、 各プロパティの動作を個別に設定することもできます:
public class Person
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Name { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? Age { get; set; }
}
次に、Newtonsoft.Json.JsonObjectAttribute
を使用して、すべてのメンバー プロパティが JSON に存在する必要があることを指定する次の例を考えてみましょう:
[JsonObject(ItemRequired = Required.Always)]
public class Person { ... }
System.Text.Json では、C# required
修飾子または JsonRequiredAttribute を各プロパティに追加することで、同じ動作を実現できます。 詳細については、「必須プロパティ」を参照してください。
public class Person
{
[JsonRequired]
public string? Name { get; set; }
public required int? Age { get; set; }
}
TraceWriter
Newtonsoft.Json
では、TraceWriter
を使用してシリアル化または逆シリアル化によって生成されたログを表示し、デバッグできます。 System.Text.Json では、ログ記録は行われません。
JToken (JObject、JArray など) と比較した JsonDocument と JsonElement
System.Text.Json.JsonDocument には、既存の JSON ペイロードからSystem.Text.Json.JsonDocumentのドキュメント オブジェクト モデル (DOM) を解析して作成する機能が用意されています。 DOM では、JSON ペイロード内のデータへのランダム アクセスが提供されます。 ペイロードを構成する JSON 要素には、JsonElement 型を使用してアクセスできます。 JsonElement
型には、JSON テキストを一般的な .NET 型に変換するための API が用意されています。 JsonDocument
では RootElement プロパティが公開されます。
.NET 6 以降では、System.Text.Json.Nodes 名前空間の JsonNode 型とその他の型を使用して、既存の JSON ペイロードから変更可能な DOM を解析および構築できます。 詳細については、「JsonNode
の使用」を参照してください。
JsonDocument は IDisposable
JsonDocument
では、データのメモリ内ビューがプールされたバッファー内に作成されます。 そのため、Newtonsoft.Json
の JObject
や JArray
とは異なり、JsonDocument
型は IDisposable
を実装し、Using ブロック内で使用される必要があります。 詳細については、「JsonDocument は IDisposable」を参照してください。
JsonDocument は読み取り専用
System.Text.Json の DOM では、JSON 要素の追加、削除、変更を行うことはできません。 このように設計されている理由は、パフォーマンスを向上させ、一般的な JSON ペイロード サイズ (つまり、< 1 MB) を解析するための割り当てを減らすためです。
JsonElement は union 構造体
JsonDocument
では、JsonElement 型 (任意の JSON 要素を含む union 構造体型) のプロパティとして RootElement
が公開されます。 Newtonsoft.Json
では JObject
、JArray
、JToken
などの専用の階層型が使用されます。 JsonElement
に対して検索と列挙を行うことができます。また、JsonElement
を使用して、JSON 要素を .NET 型に具体化することができます。
.NET 6 以降では、JsonNode 型と、JObject
、JArray
、JToken
に対応する System.Text.Json.Nodes 名前空間内の型を使用できます。 詳細については、「JsonNode
の使用」を参照してください。
JsonDocument と JsonElement でのサブ要素の検索方法
Newtonsoft.Json
の JObject
または JArray
を使用した JSON トークンの検索は、何らかのディクショナリ内での検索であるため、比較的高速になる傾向があります。 それに対し、JsonElement
での検索にはプロパティの順次検索が必要になるため、比較的低速になります (たとえば、TryGetProperty
を使用する場合)。 System.Text.Json は、検索時間ではなく、初期解析時間を最小限に抑えるように設計されています。 詳細については、「JsonDocument と JsonElement でのサブ要素の検索方法」を参照してください。
Utf8JsonReader と JsonTextReader
System.Text.Json.Utf8JsonReader は、UTF-8 でエンコードされた JSON テキスト用の、ハイ パフォーマンス、低割り当て、順方向専用のリーダーです。System.Text.Json.Utf8JsonReader または < から読み取られます。 Utf8JsonReader
は低レベルの型であり、カスタム パーサーとデシリアライザーを構築するために使用できます。
Utf8JsonReader は ref 構造体
Newtonsoft.Json
の JsonTextReader
はクラスです。 Utf8JsonReader
型は "Utf8JsonReader
" であるという点で異なります。 詳細については、「Utf8JsonReader の ref 構造体の制限事項」を参照してください。
null 許容値型に null 値を読み込む
Newtonsoft.Json
には、Nullable<T> を返す API が用意されています。たとえば、bool?
を返すことで Null
TokenType
を処理する ReadAsBoolean
などがあります。 組み込みの System.Text.Json
の API では、null 非許容値型のみが返されます。 詳細については、「null 許容値型に null 値を読み込む」を参照してください。
JSON を読み取るためのマルチターゲット
特定のターゲット フレームワークに対して Newtonsoft.Json
の使用を継続する必要がある場合は、マルチターゲットにし、実装を 2 つにすることができます。 ただし、これは簡単ではなく、いくつかの #ifdefs
とソースの複製が必要になります。 できるだけ多くのコードを共有する 1 つの方法として、Utf8JsonReader と Newtonsoft.Json.JsonTextReader
を囲む ref struct
ラッパーを作成します。 このラッパーでは、動作の違いを隔離しつつ、公開されている表面部分は統合されます。 これにより、変更を主に型の構造に隔離すると共に、新しい型を参照によって渡すことができます。 これは、Microsoft.Extensions.DependencyModel ライブラリが従っているパターンです。
Utf8JsonWriter と JsonTextWriter
System.Text.Json.Utf8JsonWriter は、String
、Int32
、DateTime
のような一般的な .NET 型から UTF-8 でエンコードされた JSON テキストを書き込むための、ハイパフォーマンスな方法です。 ライターは低レベルの型であり、カスタム シリアライザーを構築するために使用できます。
生の値を書き込む
Newtonsoft.Json
には、値が必要な生の JSON を書き込む WriteRawValue
メソッドがあります。 System.Text.Json には直接的に同等の Utf8JsonWriter.WriteRawValue があります。 詳細については、生 JSON の書き込みに関するページを参照してください。
JSON 形式をカスタマイズする
JsonTextWriter
には次の設定が含まれていますが、Utf8JsonWriter には同等のものがありません。
- QuoteChar - 文字列値を囲むために使用する文字を指定します。
Utf8JsonWriter
では常に二重引用符が使用されます。 - QuoteName - プロパティ名を引用符で囲むかどうかを指定します。
Utf8JsonWriter
では常に引用符で囲みます。
.NET 9 以降では、JsonWriterOptions 構造体によって公開されるオプションを使用して、Utf8JsonWriter のインデント文字とサイズをカスタマイズできます。
JsonTextWriter
には次の設定が含まれていますが、Utf8JsonWriter
には同等のものがありません。
- Indentation - インデントする文字数を指定します。
Utf8JsonWriter
の場合は、常に 2 文字ずつインデントします。 - IndentChar - インデントに使用する文字を指定します。
Utf8JsonWriter
では常に空白文字が使用されます。 - QuoteChar - 文字列値を囲むために使用する文字を指定します。
Utf8JsonWriter
では常に二重引用符が使用されます。 - QuoteName - プロパティ名を引用符で囲むかどうかを指定します。
Utf8JsonWriter
では常に引用符で囲みます。
Utf8JsonWriter
によって生成された JSON をこれらの方法でカスタマイズできる回避策はありません。
Timespan、Uri、または char の値を書き込む
JsonTextWriter
には、JsonTextWriter
、WriteValue
、char の値のための WriteValue
メソッドがあります。 Utf8JsonWriter
には同等のメソッドがありません。 代わりに、これらの値を文字列として書式設定し (たとえば ToString()
を呼び出します)、WriteStringValue を呼び出します。
JSON を書き込むためのマルチターゲット
特定のターゲット フレームワークに対して Newtonsoft.Json
の使用を継続する必要がある場合は、マルチターゲットにし、実装を 2 つにすることができます。 ただし、これは簡単ではなく、いくつかの #ifdefs
とソースの複製が必要になります。 できるだけ多くのコードを共有する 1 つの方法として、Utf8JsonWriter と Newtonsoft.Json.JsonTextWriter
を囲むラッパーを作成します。 このラッパーでは、動作の違いを隔離しつつ、公開されている表面部分は統合されます。 これにより、主に型の構造に変更を隔離できます。 Microsoft.Extensions.DependencyModel ライブラリは以下に従っています。
TypeNameHandling.All はサポートされていません。
System.Text.Json
から TypeNameHandling.All
-equivalent 機能を除外するという決定は意図的なものでした。 独自の型情報を指定することを JSON ペイロードに許可することは、Web アプリケーションにおいて、よくある脆弱性の原因です。 特に、TypeNameHandling.All
で Newtonsoft.Json
を構成すると、JSON ペイロード自体の中に実行可能アプリケーション全体を埋め込むことがリモート クライアントに許可されます。逆シリアル化の場合、組み込まれたコードが Web アプリケーションによって抽出され、実行されます。 詳細については、「Friday the 13th JSON attacks PowerPoint」 (13 日の金曜日の JSON 攻撃)(PowerPoint 資料から) と「Friday the 13th JSON attacks details」 (13 日の金曜日の JSON 攻撃の詳細) を参照してください。
JSON パス クエリは非サポート
JsonDocument
DOM では、JsonDocument
を使用したクエリはサポートされていません。
JsonNode DOM では、各 JsonNode
インスタンスに、そのノードへのパスを返す GetPath
メソッドが含まれます。 ただし、JSON パス クエリ文字列に基づくクエリを処理する組み込み API はありません。
詳細については、dotnet/runtime #31068 GitHub イシューを参照してください。
一部の制限は構成できません
System.Text.Json により、文字数での最大トークン サイズ (166 MB) や base 64 の場合 (125 MB) のように、一部の値に対して変更できない制限が設定されています。 詳細については、ソースコードの JsonConstants
および GitHub のイシュー dotnet/runtime #39953 を参照してください。
NaN、Infinity、-Infinity
Newtonsoft によって、NaN
、Infinity
、-Infinity
の JSON 文字列トークンが解析されます。 System.Text.Json では、JsonNumberHandling.AllowNamedFloatingPointLiterals を使用します。 この設定の使用方法の詳細については、「引用符で囲まれた数値を許可または記述する」を参照してください。
GitHub Copilot を使用して移行する
GitHub Copilot からコーディングのヘルプを取得して、IDE 内でコードを変換できます。
Visual Studio 2022 バージョン 17.8 以降を使用している場合は、Visual Studio で AI 駆動型の GitHub Copilot を試して Newtonsoft.Json
コードを移行して System.Text.Json
を使用できます。 次の例のように、プロンプトとして変換する質問とコードを Copilot のチャット ウィンドウに送信します。
Note
GitHub Copilot では AI を利用しているため、想定外のことや間違いが起こる可能性があります。 生成されたコードまたは提案を必ず確認してください。 GitHub Copilot の一般的な用途、製品への影響、人間の監視、プライバシーの詳細については、GitHub Copilot に関する FAQ を参照してください。
Copilot Chat のサンプル プロンプト
convert the following code to use System.Text.Json
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2024, 08, 08);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string output = JsonConvert.SerializeObject(product);
Console.WriteLine(output);
Copilot Chat の応答の例
To convert the code to use System.Text.Json, you can use the JsonSerializer class. Here's the updated code:
using System;
using System.Text.Json;
public class Product
{
public string Name { get; set; }
public DateTime ExpiryDate { get; set; }
public decimal Price { get; set; }
public string[] Sizes { get; set; }
}
public class Program
{
public static void Main()
{
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2024, 08, 08);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string output = JsonSerializer.Serialize(product);
Console.WriteLine(output);
}
}
This code uses System.Text.Json.JsonSerializer.Serialize to convert the Product object to a JSON string.
結果は、これらの応答例に示されているものとは異なる場合があることに注意してください。 AI モデルは非決定論的です。つまり、同じ質問を受けたときに異なる応答を返す場合があります。 これは、時間の経過に伴う学習と適応の進行、言語バリエーション、チャット履歴などのコンテキストの変更などが原因である可能性があります。
スラッシュ コマンド、参照、スレッドなどのチャット機能を使用して、インテントを設定し、範囲を絞ったコンテキストでより適切な回答を得ることができます。
たとえば、コード ファイル filename
が IDE で開かれている場合は、Copilot Chat が「#filename
を変換して System.Text.Json
を使用」するようにプロンプトでファイルを参照できます。 チャット ウィンドウまたはインライン チャットで「@workspace
を変換して System.Text.Json
を使用」を使用してソリューションを参照することもできます。
その他のリソース
.NET