web-dev-qa-db-ja.com

ASP.Netのセッションを完全に置き換える

ASP.Netセッションは、従来のWebFormsアプリには完璧に見えますが、最近のAJAXおよびMVCアプリケーションにとって深刻な問題となるいくつかのことを行います。

具体的には、ASP.Netプロバイダーにアクセスする方法は3つしかありません。

  1. 読み取りと書き込みのロック(デフォルト)-セッションはAcquireRequestStateの起動からReleaseRequestStateの起動までロックされます。ブラウザから一度に3つのリクエストが発生すると、それらはサーバーにキューイングされます。これはMVC2の唯一のオプションですが、MVC3では...

  2. 非ロック読み取り専用-セッションはロックされていませんが、に保存することはできません。一部の読み取りがセッションを再びロックしているように見えるため、これは 信頼性は低いですが のようです。

  3. セッションが無効-セッションの読み取りまたは書き込みを試みると、例外がスローされます。

ただし、最新のMVCアプリでは、多くのAJAX=イベントが一度に発生します。サーバーのキューには入れたくありませんが、セッションに書き込みできるようにしたいのですが。

私が欲しいのは4番目のモードです:ダーティリード、最後の書き込みが勝ちます

これを行う唯一の方法は、ASP.Netのセッションを完全に置き換えることだと思います(修正されてうれしいです)。 独自のプロバイダー を書くことはできますが、ASPは、それをサポートする3つのパターンのいずれかで呼び出します。ASP.Netが楽観的な同時実行を行う方法はありますか? ?

これにより、セッションへのすべての呼び出しを、基本的に同じことを行うがロックしない新しいクラスに置き換えることができます。これは苦痛です。

最小限のコード置換で、できるだけ多くの現在のセッションのもの(最も重要なのはさまざまなログのセッションID)を保持したいです。これを行う方法はありますか?理想的にはHttpContext.Current.Session私の新しいクラスを指すが、ASP.Netがリクエストをロックしない。

誰かがすでにこのようなことをしていますか?すべてのAJAXey MVCアプリが存在する場合、これはASPの新しい問題であるというのは奇妙に思われます。

45
Keith

まず第一に、MS asp.netは、セッションの「asp.netがページを処理する」コアの「webengine4.dll "dll for asp.net4」のどこかにロックされていると言います。

そして私はMSの観点からそれを言いますasp.net act correct and lock the session this way asp.netは、セッションで保持している情報の種類を認識できないため、正しい「最後の書き込み優先」を行うことができます。

ロックも正しいセッションの場合ページ全体これにより、プログラムの非常に重要な同期が得られるため、経験から、ほとんどの場合に必要であると言えます。あなたの行動。 msセッションを自分のものに置き換えた後、すべてのアクションでグローバルロックを作成する必要があります。そうしないと、二重挿入、二重アクションなどで問題が発生します。

私がここで認識している問題のを挙げます。セッションデータは、キーのリストであるSessionSateItemCollectionに保存されます。セッションがこのコレクションを読み書きする場合、それらすべてを一緒に実行します。このケースを見てみましょう。

セッションにツリー変数「VAR1」、「VAR2」、「VAR3」があります

ページ1。
getsession(実際にはすべてのデータを取得してリストに追加します)
session [VAR1] = "data1";
savesession()
結果はVAR1 = data1、VAR2 =(var2の最後のデータ)、VAR3 =(var3の最後のデータ)

ページ2
getsession(実際にはすべてのデータを取得してリストに追加します)
セッション[VAR2] = "data2";
savesession()
結果はVAR1 =(var1の最後のデータ)、VAR2 = data2、VAR3 =(var3の最後のデータ)

ページ
getsession(実際にはすべてのデータを取得してリストに追加します)
セッション[VAR3] = "data3";
savesession()
結果はVAR1 =(var1の最後のデータ)、VAR2 =(var2の最後のデータ)VAR3 = "data3"

ここで、各ページには、セッションメディアから読み取ったとき(たとえば、最後にデータベースから読み取ったとき)のデータのクローンがあることに注意してください。

この3ページをロックせずに実行させた場合、実際にはダーティリードは発生せず、「最後の書き込みが優先されます」-ここにあるのは「最後の書き込みが他のページを破壊する "です。もう一度考えてみてください。VAR1が変更されたときに、VAR2とVAR3が同じままであるのはなぜですか。 VAR2を別の場所で変更した場合はどうなりますか。

そのため、ロックなしでこれをそのままにすることはできません。

そして今、20の変数でそれを画像化しています...

可能な解決策

多くのプールのasp.netのマルチスレッドのため、プール間およびコンピューター間で同じデータを保持する唯一の方法は、共通のデータベース、またはasp.net State Serviceのようなすべてのプロセスプログラムに共通にすることです。

私は、その提案のためのプログラムを作成するよりも簡単なように、共通のデータベースを持つことを選択します。

ここで、作成したa cookieを接続すると、-to the user to the data user of the sessionとなり、完全にカスタムデータベースフィールドを使用してデータを制御します。私たちは、最後の書き込みが勝ったデータを保存または変更する方法、比較して保持する方法をロックするのが好きです。これを機能させ、すべてのニーズに合わせて作成された汎用セッションキーパーであるasp.netセッションを完全に無効にすることができますが、このような特殊なケースを処理するようには作られていません。

Asp.netは、将来のリリースでこれを機能させることができます。はい、ダーティと呼ばれる追加のフィールドを作成し、セッションでデータを保存し、ダーティフィールドを使用してデータをマージすることなどができますが、これはできません。今はそのまま動作します-少なくとも私が今まで見つけたものから。
実際、SessionStateItemにはプロパティにダーティフラグがありますが、データの保存の最後にこのマージは行われませんでした。他の誰かが既存のms asp.netセッションステートキーパーの解決策を考えているなら、私は本当に大好きです。私が今までに見つけたものを書いていますが、これは確かに方法がないことを意味するわけではありません。そのまま見つけた。

すべてが役立つことを願っています:)

カスタムSessionStateModule

この回答では https://stackoverflow.com/a/3660837/15927 カスタムモジュールを作成した後のJamesは次のように述べています:ASP.Netセッションのカスタム実装はまだ信じられませんリクエスト全体のセッションをロックします。

11
Aristos