最近、作業中の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
?
よろしくお願いします。ご意見ありがとうございます。 :)
Global.asaxはHttpApplicationを実装します-これは、その中からthisを呼び出すときに話しているものです。
HttpApplication のMSDNドキュメントには、たとえばHttpHandlerでそれを取得し、そのさまざまなプロパティにアクセスする方法の詳細が記載されています。
[〜#〜]ただし[〜#〜]
アプリケーションは、並列リクエストを処理するためにHttpApplicationの複数のインスタンスを作成でき、これらのインスタンスは再利用できるため、何らかの方法でそれを取得するだけでは、正しいインスタンスがあることを保証できません。
私も注意点を追加します-アプリケーションがクラッシュした場合、session_endが呼び出されるという保証はなく、すべてのセッションですべてのデータが失われますが、これは明らかに良いことではありません。
すべてのページにログオンすることはおそらく良い考えではないことに同意しますが、非同期ロギングが行われている中途半端な家です-ロギングクラスに詳細を送信し、時々、必要な詳細をログに記録します-それでも100%ではありませんアプリがクラッシュした場合は安定しますが、すべてを失う可能性は低くなります。
元の質問によりよく答えるには:
すべてのページリクエストは、新しい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
_を処理するかという問題はあいまいです。
あなたはすでにあなた自身の質問に答えていると思います:通常、Global.asaxとHttpContext.Current.SessionのSessionプロパティは同じです(現在のリクエストがある場合)。ただし、セッションタイムアウトの場合、アクティブなリクエストがないため、HttpContext.Currentを使用できません。
Session_Endによって呼び出されたメソッドからセッションにアクセスする場合は、それをパラメーターとして渡します。オーバーロードされたバージョンのLog()メソッドを作成します。このメソッドは、HttpSessionStateをパラメーターとして受け取り、Session_EndイベントハンドラーからTracker.Log(this.Session)を呼び出します。
ところで:あなたはどのような場合でもセッション終了イベントに頼ることができないことを知っていますか?セッション状態が進行中である場合にのみ機能します。 SQL ServerまたはStateServerを使用してセッション状態を管理する場合、セッション終了イベントは発生しません。
Session_End
イベントは、sessionstate mode
ファイルでWeb.config
がInProc
に設定されている場合にのみ発生します。セッションモードがStateServer
またはSQLServer
に設定されている場合、イベントは発生しません。
Session["SessionItemKey"]
を使用してセッション値を取得します。
さて、私はセッションアクティビティを追跡するために同じ問題に直面しています。 session_endイベントを使用する代わりに、IDisposableインターフェイスとデストラクタをsessiontrackerクラスに実装しました。 Dispose()メソッドを変更して、セッションアクティビティをDBに保存しました。ユーザーがログアウトボタンをクリックしたときに、メソッドobj.Dispose()を呼び出しました。ユーザーが誤ってブラウザを閉じた場合、GCはオブジェクトのクリーニング中にデストラクタを呼び出します(すぐにではありませんが、しばらくすると確実にこのメソッドが呼び出されます)。デストラクタメソッドは、同じDispose()メソッドを内部的に実行して、セッションアクティビティをDBに保存します。
-シャン
Session_Startイベント中、セッションはGlobal.asaxファイルで利用できます。たぶん、この時点まで何かをするのを待ちますか?