Json.Netを使用してEntity Frameworkオブジェクトをシリアル化する
-
10-07-2019 - |
質問
エンティティフレームワークオブジェクトをJavaScriptオブジェクト(JSON)にシリアル化するにはどうすればよいですか? JSON.NET を使用しようとしましたが、シリアル化しようとすると次の例外が発生します。
例外:Newtonsoft.Json.JsonSerializationException、Message ="自己参照ループ"
ヒテシュ
解決
循環参照に関して、元のDataContractシリアライザーと同じ一般的な問題を抱えているようです。相互参照するオブジェクトはメモリ内のオブジェクトグラフではかなり一般的ですが、そのような循環参照は、シリアライザーがそれを明確に考慮しない場合、シリアル化されると必然的に無限の再帰をもたらします。一般的な非バイナリシリアル化形式(XMLとJSONが最も普及している2つです)で循環参照を処理するための確立された標準がある場合は、ほとんどありません。
Microsoftは、xmlのrefセマンティクスを利用して、.NET 3.5 SP1のDataContractシリアライザーの周期的な問題を解決しました。私の知る限り、JSONにはそのようなものはありません。これが、JSON.NETがオブジェクトグラフのシリアル化を妨げている理由かもしれません。
オブジェクトグラフには、双方向ではなく、一方向にナビゲート可能な参照のみが存在するようにします(つまり、親から子へのみであり、子から親へではありません)。これらの親/子および子/親は最も一般的なタイプの循環参照。また、下位レベルの子が最終的にグラフのルートを参照し、間接的な循環グラフが作成されることもあります(ただし、これらは親/子ループよりもはるかに一般的ではありません。)
オブジェクトグラフの循環参照を削除すると、シリアル化できるようになります。
他のヒント
この問題が発生したため、ループの原因となったプロパティにNewtonsoft.Json.JsonIgnoreAttributeを追加することで解決しました。明らかに、そのプロパティはシリアル化されません。この問題を解決するために、通常、エンティティには外部参照IDと外部クラスの両方があります。これは直観的ではない(または非常に優れたオブジェクト指向)ことはわかっていますが、Julia Lermanの著書Programming Entity Framework:Code Firstで推奨されている方法です。 Entity Frameworkのいくつかの問題を解決するのに役立つことがわかりました。
public class SomeEntity
{
[JsonIgnore]
public ForeignEntity SomeForeignEntity {get;set;}
public Guid ForeignEntityId {get;set;}
}
更新:DbContextでプロキシを無効にする必要があることを言及するのを忘れました:
dataContext.Configuration.ProxyCreationEnabled = false;
サービスのコードを記述している場合(シリアライズしている可能性が高いと思われます)、これはおそらく問題ではありませんが、プロキシの作成を無効にすると失われることがあります。こちらをご覧ください: http://www.sellsbrothers.com/posts/Details/12665 詳細。
MS Web Apiを使用しているため、コントローラーを構築するときにプロキシの作成を無効にします。
public class MailingApiController : ApiController
{
public MailingApiController()
{
PreventDeepSerialization();
}
private static void PreventDeepSerialization()
{
var dataContext = Injector.Get<IIntertwyneDbContext>();
dataContext.Configuration.ProxyCreationEnabled = false;
}
....
これを回避するために、エンティティをPOCOベースのCode Firstに変換しました。これを行うには、edmxウィンドウ内を右クリックして、次を選択します。
コード生成アイテムを追加&gt; [コード]タブ&gt; EF POCO Entity Generator。
表示されない場合は、nugetでインストールする必要がある場合があることに注意してください。
ただし、実行時にEFは追跡目的でそれらのオブジェクトにプロキシクラスを追加しますが、シリアル化プロセスを台無しにする傾向があります。これを防ぐには、次のようにProxyCreationEnabledをfalseに設定するだけです。
var context = new YourEntities();
context.Configuration.ProxyCreationEnabled = false;
var results = context.YourEntity.Take(100).ToList();
次のようにデフォルトの参照ループを省略することにより、JSON.NETシリアル化データを安全に返すことができます。
return JsonConvert.SerializeObject(results, Formatting.Indented,
new jsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});