web-dev-qa-db-ja.com

「HttpContext.Current.Session」とGlobal.asax「this.Session」

最近、作業中のASP.NETプロジェクトのコードに取り組んでいます。 Session で追跡するユーザーアクティビティ(ページヒット数など)の基本的な指標を取得し、 Session_Endを介してデータをDBに保存するには、追跡ユーティリティが必要でした。 Global.asax

私はハッキングを始めました。最初のコードは正常に機能し、ページが読み込まれるたびにDBを更新しました。ただし、リクエストごとにこのDBヒットを削除し、すべてのデータを格納するためにSession_Endに依存したかったのです。

すべてのトラッキングコードは、基本的にSession変数をラップするプロパティを含め、Trackerクラスにカプセル化されています。

問題は、Session_EndメソッドでTracker.Log()を実行すると、トラッカーコードで HttpContext.Current.Session になることです。 NullReferenceException で失敗していました。 HttpContext は常にcurrentリクエストに関連しているため、これは理にかなっています。もちろん、Session_Endでは、リクエストはありません。

Global.asaxにはSessionプロパティがあります。これは実際には正常に機能しているように見えるHttpSessionStateを返します(最終的にトラッカーに挿入しました)。

しかし、興味があります。Global.asaxが使用するHttpSessionStateオブジェクトへの同じ参照をoutsideから取得するにはどうすればよいですか。 Global.asax

よろしくお願いします。ご意見ありがとうございます。 :)

13
Rob Cooper

Global.asaxはHttpApplicationを実装します-これは、その中からthisを呼び出すときに話しているものです。

HttpApplication のMSDNドキュメントには、たとえばHttpHandlerでそれを取得し、そのさまざまなプロパティにアクセスする方法の詳細が記載されています。

[〜#〜]ただし[〜#〜]

アプリケーションは、並列リクエストを処理するためにHttpApplicationの複数のインスタンスを作成でき、これらのインスタンスは再利用できるため、何らかの方法でそれを取得するだけでは、正しいインスタンスがあることを保証できません。

私も注意点を追加します-アプリケーションがクラッシュした場合、session_endが呼び出されるという保証はなく、すべてのセッションですべてのデータが失われますが、これは明らかに良いことではありません。

すべてのページにログオンすることはおそらく良い考えではないことに同意しますが、非同期ロギングが行われている中途半端な家です-ロギングクラスに詳細を送信し、時々、必要な詳細をログに記録します-それでも100%ではありませんアプリがクラッシュした場合は安定しますが、すべてを失う可能性は低くなります。

10

元の質問によりよく答えるには:

バックグラウンド

すべてのページリクエストは、新しいSessionオブジェクトを起動し、セッションストアからそれを膨らませます。これを行うには、クライアントから提供されたCookieまたは特別なパス構造(Cookieなしのセッションの場合)を使用します。このセッション識別子を使用して、セッションストアを参照し、新しいセッションオブジェクトを逆シリアル化します(これが、InProc以外のすべてのプロバイダーがシリアル化可能である必要がある理由です)。

InProcプロバイダーの場合は、セッション識別子でキー設定されたHttpCacheに格納されている参照を渡すだけです。 これが、AppDomainがリサイクルされるときにInProcプロバイダーがセッション状態をドロップする理由です(また、複数のWebサーバーがInProcセッション状態を共有できない理由

この新しく作成されて膨らんだオブジェクトは、_Context.Items_コレクションにスタックされているため、リクエストの期間中利用できます。

Sessionオブジェクトに加えた変更は、シリアル化によってセッションストアへの要求の最後に保持されます(またはInProcの場合、HttpCacheエントリが更新されます)。

_Session_End_は現在のリクエストなしで起動するため、Sessionオブジェクトはex-niloでスピンアップされ、情報はありません。 InProcセッション状態を使用している場合、HttpCacheの有効期限が_Session_End_イベントへのコールバックイベントをトリガーするため、セッションエントリは使用可能ですが、それでも_HttpContext.Cache_に最後に保存されたもののコピーです。この値は、内部メソッド(ProcessSpecialRequestと呼ばれる)によって_HttpApplication.Session_プロパティに対して格納され、そこで使用可能になります。他のすべての場合、内部的には_HttpContext.Current.Session_値から取得されます。

あなたの答え

Session_Endは常にnullコンテキストに対して起動するため、そのイベントでは常にthis.Sessionを使用し、HttpSessionStateオブジェクトをトレースコードに渡す必要があります。他のすべてのコンテキストでは、_HttpContext.Current.Session_からフェッチして、トレースコードに渡すのはまったく問題ありません。 しないでくださいただし、トレースコードがセッションコンテキストに到達するまで待ちます。

私の答え

使用しているセッションストアが_Session_End_をサポートしていることがわかっている場合を除き、_Session_End_を使用しないでください。trueからSetItemExpireCallbackを返す場合はサポートします。含まれている唯一のストアは、InProcSessionStateストアです。実行するセッションストアを作成することは可能ですが、複数のサーバーがある場合、誰が_Session_End_を処理するかという問題はあいまいです。

17
IDisposable

あなたはすでにあなた自身の質問に答えていると思います:通常、Global.asaxとHttpContext.Current.SessionのSessionプロパティは同じです(現在のリクエストがある場合)。ただし、セッションタイムアウトの場合、アクティブなリクエストがないため、HttpContext.Currentを使用できません。

Session_Endによって呼び出されたメソッドからセッションにアクセスする場合は、それをパラメーターとして渡します。オーバーロードされたバージョンのLog()メソッドを作成します。このメソッドは、HttpSessionStateをパラメーターとして受け取り、Session_EndイベントハンドラーからTracker.Log(this.Session)を呼び出します。

ところで:あなたはどのような場合でもセッション終了イベントに頼ることができないことを知っていますか?セッション状態が進行中である場合にのみ機能します。 SQL ServerまたはStateServerを使用してセッション状態を管理する場合、セッション終了イベントは発生しません。

3
M4N

Session_Endイベントは、sessionstate modeファイルでWeb.configInProcに設定されている場合にのみ発生します。セッションモードがStateServerまたはSQLServerに設定されている場合、イベントは発生しません。

Session["SessionItemKey"]を使用してセッション値を取得します。

2
Usha

さて、私はセッションアクティビティを追跡するために同じ問題に直面しています。 session_endイベントを使用する代わりに、IDisposableインターフェイスとデストラクタをsessiontrackerクラスに実装しました。 Dispose()メソッドを変更して、セッションアクティビティをDBに保存しました。ユーザーがログアウトボタンをクリックしたときに、メソッドobj.Dispose()を呼び出しました。ユーザーが誤ってブラウザを閉じた場合、GCはオブジェクトのクリーニング中にデストラクタを呼び出します(すぐにではありませんが、しばらくすると確実にこのメソッドが呼び出されます)。デストラクタメソッドは、同じDispose()メソッドを内部的に実行して、セッションアクティビティをDBに保存します。

-シャン

0
Shan

Session_Startイベント中、セッションはGlobal.asaxファイルで利用できます。たぶん、この時点まで何かをするのを待ちますか?

0
brumScouse