ASP.Net静的関数の“コンテキスト”ユーザーセッション間のクロスオーバー?
-
07-07-2019 - |
質問
ASP.Netアプリケーションで静的オブジェクトがどのように保持されるかを理解するには、助けが必要だと思います。このシナリオがあります:
クラスライブラリのsomeFile.cs:
public delegate void CustomFunction();
public static class A {
public static CustomFunction Func = null;
}
クラスライブラリのsomeOtherFile.cs:
public class Q {
public Q() {
if (A.Func != null) {
A.Func();
}
}
}
一部のASP.Netページ:
Page_Init {
A.Func = MyFunc;
}
public void MyFunc() {
System.IO.File.AppendAllText(
"mydebug.txt", DateTime.Now.ToString("hh/mm/ss.fff", Session.SessionID));
}
Page_Load {
Q myQ = new Q();
System.Threading.Thread.Sleep(20000);
mQ = new Q();
}
アイデアは、UIレベルでコールバック関数に基づいて何らかの操作を行うビジネスオブジェクトがあるということです。コールバック関数をPage_Initの静的変数に設定します(実際のコードバージョンでは、マスターページで、違いがある場合)。ページの実行は、それがどのユーザーセッションから来たものであっても、その関数のロジックを通過し、独自のデータセットで動作すると考えました。代わりに発生していると思われるのは、同時実行の問題です。
1つのユーザーセッションを実行し、そのコールバック関数の呼び出し間でスリープしている間に、別のユーザーセッションを開始します。最初のセッションがスリープから復帰すると、2番目のユーザーセッションからセッションIDを取得します。どうすればこれが可能ですか?
mydebug.txtの出力:
01/01/01.000 abababababab (session #1, first call)
01/01/05.000 cdcdcdcdcdcd (session #2, first call - started 5 seconds after session #1)
01/01/21.000 cdcdcdcdcdcd (session #1 returns after the wait but has assumed the function context from session #2!!!!!)
01/01/25.000 cdcdcdcdcdcd (session #2 returns with its own context)
関数のコンテキスト(意味、ローカルデータなど)がユーザーセッション間で上書きされるのはなぜですか?
解決
検討する可能性のある解決策の1つは、[ThreadStatic]の使用です。
http://msdn.microsoft。 com / en-us / library / system.threadstaticattribute(VS.71).aspx
スレッドごとに統計を作成します。ただし、洞窟がありますので、テストする必要があります。
他のヒント
asp.netサイトへの各リクエストが受信され、独自のスレッドで処理されます。ただし、これらのスレッドはそれぞれ同じアプリケーションに属します。つまり、静的としてマークしたものはすべてのリクエストで共有されるため、すべてのセッションとユーザーで共有されます。
この場合、ページクラスの一部である MyFunc
関数は、 A
のすべての静的 Func
メンバーの上にコピーされます。 page_initであるため、ユーザーはpage_initを実行するたびに、 all リクエストで使用される A.Func
を置き換える。
静的データは、アプリケーションドメイン全体で共有されます。 のWebアプリ。 つまり、webappでリクエストを処理するすべてのスレッドで共有され、セッション/スレッド/ユーザーにバインドされるのではなく、webapp全体にバインドされます(たとえば、各リクエストが独自の隔離された環境バーに存在するphpとは異なります)セッション変数などのいくつかのノブが提供されます。)
静的メンバーに関する他の回答の説明を改善しようとはしませんが、差し迫った問題を回避する別のコーディング方法を指摘したいと思います。
解決策として、クラスのインスタンス指向バージョンを作成して A
、ページレベルの変数に保存し、 Q
に渡すことができますページ読み込み時のコンストラクタ:
public class MyPage: Page {
private A2 _a2;
// I've modified A2's constructor here to accept the function
protected Page_Init() { this._a2 = new A2(MyFunc); }
protected Page_Load() {
Q myQ = new Q(this._a2);
// etc..
}
}
実際、早めに A2
を宣言する必要がない場合は、 Page_Load
Q のインスタンスを作成するときにインスタンス化できます。 >。
編集:他のコメントで提起した質問に答えるため、変数が共有されている理由は、リクエストが同じデリゲートを共有しているためです。詳細については、Jon Skeetの閉鎖の美しさをご覧ください。
現在のリクエストに対してのみデータを保持する場合は、 HttpContext.Items
を使用します。
http://msdn.microsoft.com/en- us / library / system.web.httpcontext.items.aspx
現在のユーザーのセッションでデータを保持したい場合(セッション状態が有効になっていると仮定)、 HttpContext.Session
を使用します。
http://msdn.microsoft.com/en- us / library / system.web.httpcontext.session.aspx