5

多層化された Asp.NET Web フォーム アプリケーションがあります。データ層には、エンティティ フレームワーク オブジェクト コンテキストのインスタンスDataAccessを実装し、プライベート フィールドとして持つというクラスがあります。IDisposableこのクラスには、エンティティのさまざまなコレクションを返す多数のパブリック メソッドがあり、破棄されるとオブジェクト コンテキストが破棄されます。

DataAccess私たちが直面してきた多くの問題により、オブジェクト コンテキスト (または のインスタンス) をサーバー上でより長くスコープ内に保持することが大きなプラスになると判断しました。Http リクエストごとに 1 つのインスタンスを持つために、この投稿HttpContext.Current.Itemsのコレクションにインスタンスを保持することを提案しました。

私が疑問に思っているのは、オブジェクトコンテキストのインスタンスをオブジェクトに格納することでどのような問題/懸念/問題が発生するのでしょうかHttpContext.Current.Session????

  • ユーザーのセッションの有効期限が切れると、Session オブジェクトがファイナライズされ、ガベージ コレクション用に設定されるため、インスタンスは適切に破棄されると想定しています。
  • ほとんどのデフォルトのブラウザー設定では、アプリが問題なく SessionId Cookie を配置できると想定しています。
  • オブジェクト コンテキストが処理するデータの量は膨大ではなく、時間の経過に伴うキャッシュと比較的少数の同時ユーザーに関して、適切なサーバー ハードウェアに問題を引き起こすことはありません。

これは比較的迅速に実装でき、多くの既存の単体テストには影響しません。

AutoFac と ServiceProvider クラスを使用してインスタンスを提供します。ObjectContext のインスタンスが必要な場合、次のようなコードによって返されます。

private static Entities GetEntities(IContext context)
{
    if (HttpContext.Current == null)
    {
        return new Entities();
    }

    if (HttpContext.Current.Session[entitiesKeyString] == null)
    {
        HttpContext.Current.Session[entitiesKeyString] = new Entities();
    }

    return (Entities)HttpContext.Current.Session[entitiesKeyString];
}

乾杯。

4

2 に答える 2

19

クラスは作業単位パターンをカプセル化することを目的としているため、セッション状態に を格納するObjectContextことは良い習慣とは言えません。データ (エンティティ) をロードし、それらを変更し、変更をコミットします (これはUOW によって追跡されます)、それで完了です。UOW オブジェクトは、長期間存続するように意図または設計されていません。

とは言っても、大きな災害を引き起こすことなく行うことができます。舞台裏で何が起こっているのかを理解していることを確認する必要があります. これを行う予定がある場合は、読み進めて、自分が何に夢中になっているかを理解し、トレードオフを認識してください。


ユーザーのセッションが期限切れになると、Session オブジェクトがファイナライズされ、ガベージ コレクション用に設定されるため、インスタンスは適切に破棄されると想定しています。

これは実際には不正確であるか、少なくとも言葉遣いに基づいているようです。セッションの期限切れ/ログアウトによって、アイテムがすぐに破棄されることはありません。それらは最終的にファイナライズ/破棄されますが、それはガベージコレクター次第であり、いつ発生するかを制御することはできません. ここでの最大の潜在的な問題は、 で接続を手動で開いた場合に、ObjectContext自動的に閉じられないことです。注意しないと、通常のユニットでは検出されないデータベース接続のリークが発生する可能性があります。テスト/統合テスト/ライブ テスト。

オブジェクト コンテキストが処理するデータの量は膨大ではなく、時間の経過に伴うキャッシュと比較的少数の同時ユーザーに関して、適切なサーバー ハードウェアに問題を引き起こすことはありません。

成長は際限がないことを覚えておいてください。特定のユーザーがあなたのサイトを 12 時間連続して使用し、1 日中さまざまなクエリを実行することを決定した場合、コンテキストはどんどん大きくなり続けます。にObjectContextは独自の内部「ガベージ コレクション」がなく、長い間使用されていないキャッシュ/追跡エンティティを清掃しません。ユースケースに基づいてこれが問題にならないと確信している場合は問題ありませんが、あなたを悩ませている主なことは、状況を制御できないという事実です.


もう 1 つの問題は、スレッド セーフです。 ObjectContextスレッドセーフではありません。通常、セッション アクセスはシリアル化されるため、1 つの要求は、同じセッションに対する別の要求が完了するまで、そのセッション状態の待機をブロックします。ただし、誰かが後で最適化、特にページ レベルの読み取り専用セッションの最適化を行うことを決定した場合、リクエストは排他ロックを保持しなくなり、さまざまな競合状態や再入の問題が発生する可能性があります。 .

最後になりましたが、もちろん、マルチユーザーの同時実行の問題です。エンティティは、破棄されるObjectContextまで永続的にキャッシュされます。別のユーザーが自分ObjectContextで同じエンティティを変更した場合、最初の所有者はその変更を知ることObjectContextありません。これらの古いデータの問題は、クエリがデータベースに移動して新しいデータが返されるのを実際に見ることができるため、デバッグが非常に困難になる可能性がありますが、ObjectContext既にキャッシュにある古い古いデータで上書きされます。私の意見では、これはおそらく、長寿命のObjectContextインスタンスを避ける最も重要な理由です。データベースから最新のデータを取得するようにコーディングしたと思っていても、ObjectContextあなたより賢いと判断し、代わりに古いエンティティをあなたに返します。


これらの問題をすべて認識しており、それらを軽減するための措置を講じている場合は、問題ありません。ObjectContextしかし、私の質問は、セッション レベルが非常に優れたアイデアであると正確に考える理由は何ですか? ObjectContextAppDomain 全体のメタデータがキャッシュされるため、作成は非常に安価な操作です。高価であるという誤った印象を受けているか、いくつかの異なる Web ページに複雑なステートフル プロセスを実装しようとしており、後者の長期的な結果は、特定のページよりもはるかに悪いと思います。をObjectContextセッションに入れるだけで害を及ぼす可能性があります。

いずれにせよそれを行う場合は、適切な理由があることを確認してください。これを行う正当な理由はそれほど多くありません。しかし、私が言ったように、それは間違いなく可能であり、結果としてあなたのアプリが爆発することはありません.


更新- 「同じセッションでの複数の要求がスレッド セーフの問題を引き起こす可能性がある」という理由でこれに反対票を投じることを検討している他の人は、ASP.NET セッション状態の概要ドキュメントの下部をお読みください。シリアル化されるのは、セッション状態の個々のアクセスだけではありません。セッションを取得するすべてのリクエストは、リクエスト全体が完了するまで解放されないセッションの排他ロックを保持します。上記の最適化のいくつかを除いて、デフォルト構成では、 の同じセッション ローカル インスタンスへの参照を保持する 2 つの同時要求が存在することはありませんObjectContext

ObjectContext上記のいくつかの理由から、セッション状態に を保存しませんが、それを作成しない限り、スレッドセーフの問題ではありません。

于 2010-03-05T05:37:01.680 に答える
3

リクエストごとに 1 つの ObjectContext を使用する必要があります。それをセッションとして保存しないでください。長期間保存された ObjectContext のデータを簡単に台無しにします。

  1. ObjectContext の規則に違反していないが、データベースの規則に違反しているデータを挿入するとどうなるでしょうか? ルールに違反する行を挿入すると、コンテキストから削除されますか? 画像の状況: 1 つのコンテキストを使用すると、あるテーブルのデータを変更し、別のテーブルに行を追加し、SaveChanges() を呼び出すという要求が突然発生します。変更の 1 つが制約違反エラーをスローします。どうやってきれいにしますか?コンテキストのクリーニングは簡単ではありません。次のリクエストで新しいコンテキストを取得するだけの方が簡単です。

  2. まだコンテキスト内にある間に、誰かがデータベースからデータを削除した場合はどうなりますか? ObjectContext はデータをキャッシュし、データがまだ存在するかどうか、または変更されているかどうかを時々確認しません:)

  3. 誰かが web.config を変更し、セッションが失われた場合はどうなりますか? ログインしたユーザーに関する情報を保存するために Session に依存したいようです。フォーム認証 Cookie は、この情報を保存するためのより信頼できる場所です。多くの状況でセッションが失われる可能性があります。

ObjectContext は短命になるように設計されています。必要に応じてリクエストで作成し、最後に破棄することをお勧めします。

リクエストごとのコンテキストが機能しない場合は、おそらく何か間違ったことをしていますが、Session を使用して悪化させないでください。

于 2010-03-05T04:41:51.450 に答える