[解決済み] JSON.NET エラー タイプの自己参照ループが検出されました。
質問
エンティティデータモデル.edmxから自動生成されたPOCOクラスをシリアライズしようとしたのですが、その際に
JsonConvert.SerializeObject
以下のようなエラーが発生しました。
エラー System.data.entity 型の自己参照ループが検出されました。
この問題を解決するにはどうしたらよいですか?
どのように解決するのですか?
これがベストな解決策だった https://docs.microsoft.com/en-us/archive/blogs/hongyes/loop-reference-handling-in-web-api
修正1: 循環参照をグローバルに無視する。
(他の多くの人と同様、私もこれを選択/試しました)
json.netのシリアライザーには、循環参照を無視するオプションがあります。以下のコードを
WebApiConfig.cs
ファイルを作成します。
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore;
この単純な修正では、シリアライザが参照を無視するようになり、ループが発生します。しかし、これには限界があります。
- データは、ループする参照情報を失う
- この修正はJSON.netにのみ適用されます。
- 深い参照連鎖がある場合、参照のレベルを制御することができない
この修正を非apiのASP.NETプロジェクトで使用したい場合は、上記の行を
Global.asax.cs
を、最初に追加してください。
var config = GlobalConfiguration.Configuration;
で使用したい場合は
.Net コア
プロジェクトでは
Startup.cs
としています。
var mvc = services.AddMvc(options =>
{
...
})
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
修正2: グローバルに循環参照を保持する
この2つ目の修正は、1つ目の修正と同様です。コードを次のように変更するだけです。
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling
= Newtonsoft.Json.PreserveReferencesHandling.Objects;
この設定を適用すると、データの形状が変更されます。
[
{
"$id":"1",
"Category":{
"$id":"2",
"Products":[
{
"$id":"3",
"Category":{
"$ref":"2"
},
"Id":2,
"Name":"Yogurt"
},
{
"$ref":"1"
}
],
"Id":1,
"Name":"Diary"
},
"Id":1,
"Name":"Whole Milk"
},
{
"$ref":"3"
}
]
idと$refはすべての参照を保持し、オブジェクトグラフレベルをフラットにしますが、クライアントコードはデータを消費するために形状変化を知る必要があり、それは同様にJSON.NETシリアライザーにのみ適用されます。
修正3:参照属性を無視し保存する
この修正は、モデルクラス上の属性を装飾し、モデルまたはプロパティレベルでシリアライズの動作を制御するものです。プロパティを無視するために
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public virtual ICollection<Product> Products { get; set; }
}
JsonIgnoreはJSON.NET用、IgnoreDataMemberはXmlDCSerializer用です。 リファレンスを保持するため。
// Fix 3
[JsonObject(IsReference = true)]
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
// Fix 3
//[JsonIgnore]
//[IgnoreDataMember]
public virtual ICollection<Product> Products { get; set; }
}
[DataContract(IsReference = true)]
public class Product
{
[Key]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual Category Category { get; set; }
}
JsonObject(IsReference = true)]
はJSON.NET用で
[DataContract(IsReference = true)]
はXmlDCSerializer用です。以下のことに注意してください。
DataContract
をクラス上に追加する必要があります。
DataMember
を、シリアライズしたいプロパティに追加してください。
この属性は、jsonとxmlの両方のシリアライザに適用することができ、モデル・クラスにより多くの制御を与えることができます。
関連
-
[解決済み】「未割り当てのローカル変数を使用」とはどういう意味ですか?
-
[解決済み】"出力タイプがクラスライブラリのプロジェクトは直接起動できない"
-
[解決済み】ここで「要求URIに一致するHTTPリソースが見つかりませんでした」となるのはなぜですか?
-
[解決済み] 'SubSonic.Schema .DatabaseColumn' 型のオブジェクトをシリアライズする際に、循環参照が検出されました。
-
[解決済み] DBNullから他の型にオブジェクトをキャストすることができない
-
[解決済み] UnityでOnCollisionEnterが呼ばれない
-
[解決済み】C#のequal to演算子でtextとvarcharのデータ型は互換性がない
-
[解決済み】インデックスが範囲外でした。コレクションパラメータname:indexのサイズより小さく、非負でなければなりません。
-
[解決済み】ファイルやアセンブリ、またはその依存関係の1つをロードできませんでした。
-
[解決済み] JSON.Netの自己参照ループが検出されました。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】指定されたキャストが有効でない?
-
[解決済み】ここで「要求URIに一致するHTTPリソースが見つかりませんでした」となるのはなぜですか?
-
[解決済み】統合マネージドパイプラインモードで適用されないASP.NETの設定が検出された
-
[解決済み】トランスポート接続からデータを読み取れない:既存の接続は、リモートホストによって強制的に閉じられました。
-
[解決済み】取り消せないメンバはメソッドのように使えない?
-
[解決済み] 'IEnumerable<SelectListItem>' 型の ViewData アイテムで、キーが国であるものは存在しない。
-
[解決済み】MetadataException: 指定されたメタデータ・リソースをロードできない
-
[解決済み】HRESULTからの例外:0x800A03ECエラー
-
[解決済み】URLから画像をダウンロードする方法
-
[解決済み] JSON.Netの自己参照ループが検出されました。