はじめ
に Web アプリケーションのようなステートレス環境では、セッション状態の概念を理解することは実際には意味がありません。それにもかかわらず、効果的な状態管理は、ほとんどの Web アプリケーションにとって必須の機能です。 Microsoft ASP.NET および他の多くのサーバー側プログラミング環境は、アプリケーションがユーザーごとおよびアプリケーションごとに永続的なデータを保存できるようにする抽象化レイヤーを提供します。
Web アプリケーションのセッション状態は、アプリケーションがさまざまなリクエストにわたってキャッシュおよび取得するデータであることに注意することが重要です。セッションは、サイトへの接続中にユーザーによって送信されたすべてのリクエストを表し、セッション状態は、セッション中にユーザーによって生成および消費された永続データのコレクションです。各セッションの状態は互いに独立しており、ユーザー セッションが終了すると存在しなくなります。
セッション状態は、HTTP プロトコルおよび仕様を構成する論理エンティティのいずれとも対応しません。セッションは、従来の ASP や ASP.NET などのサーバー側開発環境によって構築される抽象化レイヤーです。 ASP.NET がセッション状態を表示する方法、およびセッション状態が内部的に実装される方法は、プラットフォームのインフラストラクチャによって異なります。したがって、従来の ASP と ASP.NET はまったく異なる方法でセッション状態を実装しており、ASP.NET の次のバージョンではさらなる改善と機能強化が期待されています。
この記事では、ASP.NET 1.1 でセッション状態を実装する方法と、マネージド Web アプリケーションでセッション状態管理を最適化する方法について説明します。
ASP.NET セッション状態の概要
セッション状態は HTTP インフラストラクチャの一部ではありません。つまり、受信リクエストごとにセッション状態をバインドする構造コンポーネントが必要です。ランタイム環境 (従来の ASP または ASP.NET) は、Session などのキーワードを受け入れ、それを使用してサーバーに保存されているデータのブロックを示すことができます。 Session オブジェクトへの呼び出しを正常に解決するには、ランタイム環境は、処理中のリクエストの呼び出しコンテキストにセッション状態を追加する必要があります。これがどのように行われるかはプラットフォームによって異なりますが、これはステートフル Web アプリケーションの基本です。
従来の ASP では、セッション状態は、asp.dll ライブラリに含まれるフリースレッドの COM オブジェクトとして実装されます。 (興味がありませんか? このオブジェクトの CLSID は、実際には D97A6DA0-A865-11cf-83AF-00A0C90C2BD8 です。) このオブジェクトには、名前と値のペアのコレクションとして編成されたデータが格納されます。 「名前」プレースホルダーは情報を取得するために使用されるキーを表し、「値」プレースホルダーはセッション状態に格納される内容を表します。名前と値のペアはセッション ID ごとにグループ化されているため、各ユーザーには自分が作成した名前と値のペアのみが表示されます。
ASP.NET では、セッション状態のプログラミング インターフェイスは従来の ASP とほぼ同じです。ただし、それらの基本的な実装は完全に異なります。前者は後者よりも柔軟でスケーラブルで、強力なプログラミング機能を備えています。 ASP.NET セッション状態について詳しく説明する前に、ASP.NET セッション インフラストラクチャの構造上の機能の一部を簡単に確認してみましょう。
ASP.NET では、受信した HTTP 要求はすべて HTTP モジュールを介してパイプ処理されます。各モジュールは、リクエストによって運ばれる大量の情報をフィルタリングおよび変更できます。各リクエストに関連付けられた情報は「呼び出しコンテキスト」と呼ばれ、プログラミングでは HttpContext オブジェクトによって表されます。リクエスト コンテキストが提供する Items コレクションは単なるデータ コンテナですが、リクエスト コンテキストを状態情報の別のコンテナとして考える必要はありません。 HttpContext オブジェクトは、要求の処理に必要な時間を超える限られた有効期間を持つという点で、他のすべての状態オブジェクト (セッション、アプリケーション、キャッシュなど) とは異なります。リクエストが一連の登録された HTTP モジュールを通過すると、その HttpContext オブジェクトには状態オブジェクトへの参照が含まれます。最終的にリクエストを処理できるようになると、関連付けられた呼び出しコンテキストが特定のセッション (セッション) とグローバル状態オブジェクト (アプリケーションとキャッシュ) にバインドされます。
各ユーザーのセッション状態の設定を担当する HTTP モジュールは、SessionStateModule です。このモジュールの構造は、ASP.NET アプリケーションに多数のセッション状態関連のサービスを提供する IHttpModule インターフェイスに基づいて設計されています。セッション ID の生成、Cookie を使用しないセッション管理、外部状態プロバイダーからのセッション データの取得、リクエストの呼び出しコンテキストへのデータのバインドが含まれます。
HTTP モジュールはセッション データを内部に保存しません。セッション状態は常に「状態プロバイダー」と呼ばれる外部コンポーネントに保存されます。状態プロバイダーはセッション状態データを完全にカプセル化し、IStateClientManager インターフェイスのメソッドを通じて他の部分と通信します。セッション状態 HTTP モジュールは、このインターフェイス上のメソッドを呼び出して、セッション状態を読み取り、保存します。 ASP.NET 1.1 は、表 1 に示すように、3 つの異なる状態プロバイダーをサポートしています。
表 1: ステータス クライアント プロバイダー
プロバイダーの説明
InProc セッション値は、ASP.NET ワーカー プロセス (Microsoft® Windows Server® 2003 の aspnet_wp.exe または w3wp.exe) のメモリ内にアクティブなオブジェクトのままになります。これはデフォルトのオプションです。
StateServer セッション値はシリアル化され、別のプロセス (aspnet_state.exe) のメモリに保存されます。このプロセスは他のコンピュータでも実行できます。
SQLServer セッション値はシリアル化され、Microsoft® SQL Server® テーブルに保存されます。 SQL Server のインスタンスはローカルまたはリモートで実行できます。
セッション状態 HTTP モジュールは、現在選択されている状態プロバイダーを web.config ファイルの <sessionState> セクションから読み取ります。
<sessionState mode="InProc | StateServer | SQLServer />;
mode 属性の値に応じて、セッション状態はさまざまな手順を通じてさまざまなプロセスから取得され、さまざまなプロセスに保存されます。デフォルトでは、セッション状態はローカルに保存されます。 ASP.NET ワーカー プロセス。特殊な場合は、セッション状態は ASP.NET キャッシュ オブジェクトの専用スロットに保存されます (プログラムからはアクセスできません)。リモート プロセス (Windows など) にも、セッション状態を保存できます。 3 番目のオプションは、SQL Server 2000 によって管理される専用のデータベース テーブルにセッション状態を保存することです。HTTP
モジュールは、要求の先頭でセッション値を逆シリアル化して、ディクショナリ オブジェクトにします。 (実際には HttpSessionState 型のオブジェクト) は、クラス (HttpContext や Page など) によって公開される Session プロパティを通じてプログラムでアクセスされ、リクエストが正常に完了すると、すべてのステータス値がシリアル化されます。
図 1 は、
要求された ASP.NET ページとセッション値の間の通信を示しています。各ページで使用されるコードは、ページ クラスの Session 属性に関連しています。従来のASPと同じです。
図 1: ASP.NET 1.1 のセッション状態のアーキテクチャ
セッション状態の物理値は、要求の完了に必要な時間の間ロックされます。このロックは HTTP モジュールによって内部的に管理され、セッション状態へのアクセスを同期するために使用されます。
セッション状態モジュールは、アプリケーションの状態プロバイダーをインスタンス化し、web.config ファイルから読み取った情報を使用して初期化します。次に、各プロバイダーは独自の初期化操作を続行します。プロバイダーの種類に応じて、その初期化操作は大きく異なります。たとえば、SQL Server 状態マネージャーは特定のデータベースへの接続を開き、アウトプロセス マネージャーは指定された TCP ポートをチェックします。一方、InProc 状態マネージャーはコールバック関数への参照を保存します。このアクションは、要素がキャッシュから削除されるときに実行され、アプリケーションの Session_OnEnd イベントをトリガーするために使用されます。
セッション状態への同期アクセス
Web ページが非常に単純かつ直観的に Session プロパティを呼び出すとどうなるでしょうか?次の面倒なコードに示すように、多くの操作がバックグラウンドで実行されます。
int siteCount = Convert.ToInt32(Session["Counter"]);
上記のコードは、実際にローカル メモリ内の HTTP モジュールによって作成されたセッション値にアクセスします。特定の状態プロバイダーからデータを読み取ります (図 1 を参照)。他のページもセッション状態に同期的にアクセスしようとするとどうなりますか?この場合、現在のリクエストは、一貫性のないデータまたは古いデータの処理を停止する可能性があります。これを回避するために、セッション状態モジュールはリーダー/ライターのロック メカニズムを実装し、状態値へのアクセスをキューに入れます。セッション状態に対する書き込み権限を持つページは、リクエストが終了するまでそのセッションのライター ロックを保持します。
ページは、@Page ディレクティブの EnableSessionState プロパティを true に設定することで、セッション状態の書き込み権限を要求できます。 (これはデフォルト設定です)。ただし、EnableSessionState プロパティが ReadOnly に設定されている場合など、ページはセッション状態への読み取り専用アクセスを持つこともできます。この場合、モジュールは、そのページのリクエストが終了するまで、そのセッションのリーダー ロックを保持します。その結果、同時読み取りが発生します。
ページリクエストがリーダーロックを設定すると、同じセッション内の他の同時リクエストはセッション状態を更新できなくなりますが、少なくとも読み取りは可能になります。つまり、セッションに対して読み取り専用リクエストが現在処理されている場合、保留中の読み取り専用リクエストはフル アクセスを必要とするリクエストよりも高い優先順位を持ちます。ページ要求がセッション状態のライター ロックを設定すると、コンテンツの読み取りまたは書き込みに関係なく、他のすべてのページがブロックされます。たとえば、2 つのフレームが同時にセッションに書き込もうとした場合、一方のフレームは書き込みができるようになる前に、もう一方のフレームが完了するまで待機する必要があります。
状態プロバイダーの比較
デフォルトでは、ASP.NET アプリケーションはセッション状態をワーカー プロセスのメモリ、具体的には Cache オブジェクトの専用スロットに保存します。 InProc モードが選択されている場合、セッション状態は Cache オブジェクト内のスロットに保存されます。このスロットはプライベート スロットとしてマークされており、プログラムからアクセスすることはできません。つまり、ASP.NET データ キャッシュ内のすべての項目を列挙した場合、指定されたセッション状態に類似したオブジェクトは返されません。キャッシュ オブジェクトは、プライベート スロットとパブリック スロットという 2 種類のスロットを提供します。プログラマはパブリック スロットを追加して処理できますが、プライベート スロットはシステム (具体的には system.web パーツで定義されたクラス) によってのみ使用できます。
各アクティブなセッションの状態は、キャッシュ内の専用スロットを占有します。スロットの名前はセッション ID に基づいて付けられ、その値は SessionStateItem という名前の宣言されていない内部クラスのインスタンスです。 InProc 状態プロバイダーはセッション ID を取得し、キャッシュ内の対応する要素を取得します。その後、SessionStateItem オブジェクトの内容が HttpSessionState ディクショナリ オブジェクトに入力され、アプリケーションによって Session プロパティを通じてアクセスされます。 ASP.NET 1.0 には、Cache オブジェクトのプライベート スロットをプログラムで列挙可能にするバグがあることに注意してください。 ASP.NET 1.0 で次のコードを実行すると、現在アクティブな各セッション状態に含まれるオブジェクトに対応する項目を列挙できます。
foreach(キャッシュ内のDictionaryEntry要素)
{
Response.Write(elem.Key + ": " + elem.Value.ToString());
、
キャッシュされたコンテンツを列挙するときに、システム スロットはリストされなくなります。
InProc はおそらくこれまでで最も高速なアクセス オプションです。ただし、セッションに保存されるデータが増えると、Web サーバーが消費するメモリも増え、パフォーマンスが低下するリスクが高まる可能性があることに注意してください。アウトプロセス ソリューションを使用する予定がある場合は、シリアル化と逆シリアル化によって起こり得る影響を慎重に検討する必要があります。アウトプロセス ソリューションでは、Windows NT サービス (aspnet_state.exe) または SQL Server テーブルを使用してセッション値を保存します。したがって、セッション状態は ASP.NET ワーカー プロセスの外側に残り、セッション状態と実際のストレージ メディアの間でシリアル化および逆シリアル化するには、追加のコード層が必要になります。これはリクエストが処理されるたびに発生するため、最大限に最適化する必要があります。
セッション データは外部リポジトリからローカル セッション ディクショナリにコピーする必要があるため、リクエストにより 15% (プロセス外) から 25% (SQL Server) の範囲でパフォーマンスが低下します。これは単なる概算ですが、最小の影響に近いはずであり、最大の影響はこれよりもはるかに大きくなることに注意してください。実際、この推定では、セッション状態に実際に保存される型の複雑さは完全には考慮されていません。
アウトプロセス ストレージ シナリオでは、セッション状態がより長く存続し、Microsoft® インターネット インフォメーション サービス (IIS) および ASP.NET の障害から保護されるため、アプリケーションがより強力になります。セッション状態をアプリケーションから分離することにより、既存のアプリケーションを Web ファームおよび Web ガーデン アーキテクチャに簡単に拡張することもできます。さらに、セッション状態は外部プロセスに保存されるため、プロセス ループによる定期的なデータ損失のリスクが本質的に排除されます。
ここでは Windows NT サービスの使用方法を説明します。前述したように、NT サービスは aspnet_state.exe という名前のプロセスで、通常は C:WINNTMicrosoft.NETFrameworkv1.1.4322 フォルダーにあります。
実際のディレクトリは、実際に実行している Microsoft® .NET Framework のバージョンによって異なります。状態サーバーを使用する前に、サービスが準備ができており、セッション ストレージ デバイスとして使用されるローカルまたはリモート コンピューター上で実行されていることを確認する必要があります。状態サービスは ASP.NET の一部であり、ASP.NET とともにインストールされるため、追加のインストーラーを実行する必要はありません。デフォルトでは、ステータス サービスは実行されていないため、手動で開始する必要があります。 ASP.NET アプリケーションは、ロードされた直後に状態サーバーへの接続を確立しようとします。したがって、サービスは準備ができて実行されている必要があります。そうでない場合は、HTTP 例外がスローされます。次の図は、サービスのプロパティ ダイアログ ボックスを示しています。
図 2: [ASP.NET ステート サーバーのプロパティ] ダイアログ ボックス
ASP.NET アプリケーションは、セッション状態サービスが配置されているコンピューターの TCP/IP アドレスを指定する必要があります。次の設定をアプリケーションの web.config ファイルに入力する必要があります。
<設定>;
<システム.ウェブ>;
<セッション状態
モード = "状態サーバー"
stateConnectionString="tcpip=expoware:42424" />;
</system.web>;
</configuration>;
stateConnectionString 属性には、コンピュータの IP アドレスとデータ交換に使用されるポートが含まれます。デフォルトのコンピュータ アドレスは 127.0.0.1 (localhost)、デフォルトのポートは 42424 です。コンピュータを名前で示すこともできます。ローカルまたはリモート コンピューターの使用は、コードに対して完全に透過的です。 ASCII 以外の文字は名前に使用できず、ポート番号は必須であることに注意してください。
アウトプロセス セッション ストレージを使用する場合、ASP.NET ワーカー プロセスに何が起こっても、セッション状態は引き続き存在し、将来使用できます。サービスが中断された場合、データは保持され、サービスが復元されたときに自動的に取得されます。ただし、ステータス プロバイダー サービスが停止または失敗すると、データが失われます。アプリケーションを強力にしたい場合は、StateServer モードではなく SQLServer モードを使用してください。
<設定>;
<システム.ウェブ>;
<セッション状態
モード="SQLサーバー"
sqlConnectionString="server=127.0.0.1;uid=<ユーザーID>;;pwd=<パスワード>;;" />;
</system.web>;
</configuration>;
sqlConnectionString 属性を通じて接続文字列を指定できます。属性文字列にはユーザー ID、パスワード、サーバー名が含まれている必要があることに注意してください。この情報はデフォルトで固定名になっているため、データベースや初期カタログなどのタグを含めることはできません。ユーザー ID とパスワードは、統合されたセキュリティ設定に置き換えることができます。
データベースを作成するにはどうすればよいですか? ASP.NET には、データベース環境を構成するための 2 組のスクリプトが用意されています。最初のスクリプトのペアは、InstallSqlState.sql および UninstallSqlState.sql という名前で、セッション状態 NT サービスと同じフォルダーにあります。 ASPState という名前のデータベースといくつかのストアド プロシージャを作成します。ただし、データは SQL Server の一時記憶域である TempDB データベースに保存されます。これは、SQL Server コンピュータを再起動すると、セッション データが失われることを意味します。
この制限を回避するには、2 番目のスクリプトのペアを使用します。 2 番目のスクリプト ペアの名前は、InstallPersistSqlState.sql と UninstallPersistSqlState.sql です。この場合、ASPState データベースが作成されますが、テーブルは同じデータベース内に作成され、永続的になります。 SQL Server のセッション サポートをインストールすると、セッション状態データベース内の期限切れのセッションを削除するジョブも作成されます。ジョブは ASPState_Job_DeleteExpiredSessions という名前で、常に実行されています。このジョブが正しく動作するには、SQLServerAgent サービスが実行されている必要があることに注意してください。
どのモードを選択しても、セッション状態の操作をコーディングする方法は変わりません。通常どおり、いつでも Session プロパティを操作し、値の読み取りと書き込みを行うことができます。動作の違いはすべて、より低い抽象レベルで処理されます。状態のシリアル化は、おそらくセッション モード間の最も重要な違いです。
状態のシリアル化と逆シリアル化 イン
プロセス モードを使用する場合、オブジェクトはそれぞれのクラスのアクティブなインスタンスとしてセッション状態に保存されます。実際のシリアル化と逆シリアル化が発生しない場合、作成したオブジェクト (シリアル化できないオブジェクトや COM オブジェクトを含む) を実際にセッションに保存でき、それらへのアクセスにそれほどコストがかからないことを意味します。アウトプロセス状態プロバイダーを選択する場合は、別の話になります。
アウトプロセス アーキテクチャでは、セッション値はローカル ストレージ メディア (外部 AppDomain データベース) から、リクエストを処理する AppDomain のメモリにコピーされます。このタスクを実行するにはシリアル化/逆シリアル化レイヤーが必要であり、プロセス外状態プロバイダーの主要なコストの 1 つとなります。この状況がコードに与える主な影響は、セッション ディクショナリに格納できるのはシリアル化可能なオブジェクトのみであることです。
ASP.NET では、関係するデータの種類に応じて 2 つの方法を使用してデータをシリアル化および逆シリアル化します。基本的な型の場合、ASP.NET は最適化された内部シリアライザーを使用します。オブジェクトやユーザー定義クラスなどの他の型の場合、ASP.NET は .NET バイナリ フォーマッタを使用します。基本タイプには、文字列、日時、ブール値、バイト、文字、およびすべての数値タイプが含まれます。これらの型の場合、カスタムのシリアライザーを使用した方が、デフォルトの共通 .NET バイナリ フォーマッタを使用するよりも高速です。
最適化されたシリアライザーは公開されておらず、文書化されていません。これは単なるバイナリ リーダー/ライターであり、シンプルだが効果的なストレージ アーキテクチャを使用しています。シリアライザーは、BinaryWriter クラスを使用して型のバイト表現を書き込み、次にその型に対応する値のバイト表現を書き込みます。シリアル化されたバイトを読み取る場合、クラスは最初にバイトを抽出し、読み取るデータ型を検出してから、BinaryReader クラスの型固有の ReadXxx メソッドを呼び出します。
ブール型と数値型のサイズはよく知られていますが、文字列のサイズは知られていないことに注意してください。基礎となるデータ ストリームでは、文字列には常に固定長 (一度に書き込まれる 7 ビット整数コード) が接頭辞として付けられ、リーダーはこの事実を利用して文字列の正しいサイズを決定します。日付値は、日付を構成するトークンの合計数のみを書き込むことによって保存されます。したがって、セッションをシリアル化するには、日付の型が Int64 である必要があります。
含まれるクラスがシリアル化可能としてマークされている限り、BinaryFormatter クラスを使用して、より複雑なオブジェクト (カスタム オブジェクトも同様) に対してシリアル化操作を実行できます。すべての非基本タイプは同じタイプ ID によって識別され、基本タイプと同じデータ ストリームに格納されます。全体的に、シリアル化操作により 15% ~ 25% のパフォーマンス低下が発生する可能性があります。ただし、これは基本型を使用した場合の概算値です。使用する型が複雑であればあるほど、オーバーヘッドが大きくなります。
プリミティブ型を広範囲に使用しない限り、効率的なセッション データ ストレージを実装することは困難です。したがって、少なくとも理論上は、3 つのセッション スロットを使用してオブジェクトの 3 つの異なる文字列プロパティを保存する方が、オブジェクト全体をシリアル化するよりも優れています。しかし、シリアル化したいオブジェクトに 100 個のプロパティが含まれている場合はどうなるでしょうか? 100 スロットを使用しますか? それとも 1 スロットだけ使用しますか?多くの場合、より良いアプローチは、複雑な型を複数の単純な型に変換することです。このアプローチは型コンバーターに基づいています。 「型コンバーター」は、型の主要なプロパティを文字列のコレクションとして返す軽量のシリアライザーです。型コンバーターは、属性を使用して基本クラスにバインドされる外部クラスです。どのプロパティをどのように保存するかは、タイプライターが決定します。型コンバーターは ViewState ストレージにも役立ち、バイナリ フォーマッタよりも効率的なセッション ストレージの方法を表します。
セッションのライフ サイクル
ASP.NET セッション管理に関する重要な点は、セッション状態オブジェクトのライフ サイクルは、最初の項目がメモリ内ディクショナリに追加されたときにのみ開始されるということです。 ASP.NET セッションは、次のコード スニペットが実行された後にのみ開始されたとみなされます。
Session["MySlot"] = "Some data";
通常、セッション ディクショナリにはオブジェクト タイプが含まれており、データを逆方向に読み取るには、戻り値をより具体的なタイプに変換する必要があります。
string data = (string) Session["MySlot"];
ページがデータをセッションに保存すると、値は HttpSessionState クラスに含まれる特別に作成された辞書クラスにロードされます。現在処理されているリクエストが完了すると、ディクショナリの内容が状態プロバイダーにロードされます。データがプログラムによってディクショナリに追加されなかったためにセッション状態が空の場合、データは記憶媒体にシリアル化されず、さらに重要なことに、ASP.NET キャッシュ、SQL Server、または NT State Services で提供されません。現在のセッションを追跡するためのスロット。これはパフォーマンス上の理由によるものですが、セッション ID の処理方法に重要な影響を及ぼします。セッション ディクショナリにデータが保存されるまで、リクエストごとに新しいセッション ID が生成されます。
セッション状態を処理中のリクエストに関連付ける必要がある場合、HTTP モジュールはセッション ID (開始リクエストでない場合) を取得し、構成された状態プロバイダーでそれを探します。データが返されない場合、HTTP モジュールはリクエストの新しいセッション ID を生成します。これは、次のページで簡単にテストできます:
<%@ Page Language="C#" Trace="true" %>;
</html>;
<本文>;
<form runat="サーバー">;
<asp:button runat="server" text="Click" />;
</フォーム>;
</ボディ>;
</html>;
ボタンをクリックしてページに戻るたびに、新しいセッション ID が生成され、追跡情報が記録されます。
図 3: セッション ディクショナリにデータを保存しないアプリケーションでは、リクエストごとに新しいセッション ID が生成されます。
Session_OnStart イベントについてはどうでしょうか?イベントはリクエストごとに発生するのでしょうか?アプリケーションが Session_OnStart ハンドラーを定義している場合、セッション状態が空であっても、セッション状態は常に保存されます。したがって、セッション ID は、最初のリクエスト以降のすべてのリクエストで常に一定です。 Session_OnStart ハンドラーは、絶対に必要な場合にのみ使用してください。
セッションがタイムアウトするか放棄された場合、次回ステートレス アプリケーションにアクセスするときにセッション ID は変更されません。セッション状態が期限切れになった場合でも、セッション ID はブラウザー セッションが終了するまで存続するように設計されています。つまり、ブラウザー インスタンスが同じである限り、複数のセッションを表すために常に同じセッション ID が使用されます。
Session_OnEnd イベントはセッションの終了をマークし、セッションの終了に必要なクリーンアップ コードを実行するために使用されます。ただし、このイベントは InProc モードでのみサポートされる、つまり、セッション データが ASP.NET ワーカー プロセスに保存されている場合にのみサポートされることに注意してください。 Session_OnEnd イベントが発生するには、まずセッション状態が存在する必要があります。つまり、一部のデータがセッション状態に格納され、少なくとも 1 つのリクエストが完了する必要があります。
InProc モードでは、アイテムとしてキャッシュに追加されるセッション状態には、可変の有効期限ポリシーが与えられます。可変有効期限とは、アイテムが一定期間内に使用されない場合、アイテムが削除されることを意味します。この期間中に処理されたリクエストの有効期限はリセットされます。セッション状態項目の間隔はセッション タイムアウトに設定されます。セッション状態の有効期限をリセットするために使用される手法は非常にシンプルで直感的です。セッション HTTP モジュールは、ASP.NET キャッシュに保存されているセッション状態アイテムを読み取るだけです。 ASP.NET Cache オブジェクトの内部構造がわかっている場合、モジュールは変数の有効期限をリセットするための計算を実行します。したがって、キャッシュされたアイテムの有効期限が切れると、セッションはタイムアウトになります。
期限切れのアイテムはキャッシュから自動的に削除されます。状態セッション モジュールは、このプロジェクトの有効期限ポリシーの一部として削除コールバック関数も表します。キャッシュは自動的に削除関数を呼び出し、その後、Session_OnEnd イベントを発生させます。アプリケーションがアウトプロセス コンポーネントを通じてセッション管理を実行する場合、終了イベントは決して発生しません。
Cookie のないセッション
アクティブな各 ASP.NET セッションは、URL で許可されている文字のみで構成される 120 ビット文字列を使用して識別されます。セッション ID は、乱数生成器 (RNG) 暗号化プロバイダーを使用して生成されます。サービス プロバイダーは、ランダムに生成された 15 個の数値のシーケンス (15 バイト x 8 ビット = 120 ビット) を返します。次に、乱数の配列が有効な URL 文字にマッピングされ、文字列として返されます。
セッション ID 文字列はブラウザに送信され、Cookie (従来の ASP と同様) または変更された URL のいずれかの方法でサーバー アプリケーションに返されます。デフォルトでは、セッション状態モジュールはクライアント側で HTTP Cookie を作成しますが、セッション ID 文字列を埋め込む変更された URL を使用することもできます (特に Cookie をサポートしていないブラウザの場合)。どの方法が使用されるかは、アプリケーションの web.config ファイルに保存されている構成設定によって異なります。セッション設定を構成するには、<sessionState> セクションと Cookieless 属性を使用できます。
<sessionState cookieless="true|false" />;
デフォルトでは、Cookieless 属性は false で、Cookie が使用されることを示します。実際、Cookie は Web ページによってクライアントのハード ドライブに配置される単なるテキスト ファイルです。 ASP.NET では、Cookie は HttpCookie クラスのインスタンスによって表されます。通常、Cookie には名前、値のセット、および有効期限が含まれます。 Cookieless 属性が false に設定されている場合、セッション状態モジュールは実際に ASP.NET_SessionId という名前の Cookie を作成し、そこにセッション ID を保存します。次の疑似コードは、Cookie を作成するプロセスを示しています
。
sessionCookie = new HttpCookie("ASP.NET_SessionId", sessionID);
sessionCookie.Path = "/";
セッション Cookie の有効期限は非常に短く、リクエストが成功するたびに有効期限が更新されます。 Cookie の Expires 属性は、クライアントでの Cookie の有効期限を示します。セッション Cookie が明示的に設定されていない場合、Expires プロパティはデフォルトで DateTime.MinValue に設定されます。これは、.NET Framework で許可される時間の最小単位です。
セッション Cookie を無効にするには、次のように構成ファイルで Cookieless 属性を true に設定します
。
<システム.ウェブ>;
<sessionState Cookieless="true" />;
</system.web>;
</configuration>;
この時点で、次の URL のページを要求すると仮定します。
http://www.contoso.com/sample.aspx
ブラウザーのアドレス バーに表示される実際のコンテンツは異なり、セッション ID が含まれています。例:
http://www.contoso.com/(5ylg0455mrvws1uz5mmaau45)/sample.aspx
セッション状態 HTTP モジュールをインスタンス化するときに、モジュールは Cookieless 属性の値を確認します。 true の場合、リクエスト (HTTP 302) は、ページ名の直前にあるセッション ID を含む変更された仮想 URL にリダイレクトされます。リクエストが再度処理されると、セッション ID がリクエストに含まれます。新しいセッションを開始するリクエストが行われた場合、HTTP モジュールは新しいセッション ID を生成し、リクエストをリダイレクトします。リクエストがポストバックされると、ポストバックでは相対 URL が使用されるため、セッション ID はすでに存在します。
Cookie なしのセッションを使用する場合の欠点は、絶対 URL が呼び出された場合にセッション状態が失われることです。 Cookie を使用すると、アドレス バーをクリアして別のアプリケーションに移動し、その後、前のアプリケーションに戻って同じセッション値を取得できます。セッション Cookie が無効になっているときにこれを行うと、セッション データが失われます。たとえば、次のコードはセッションを中断します。
<a runat="server" href="/code/page.aspx">;Click</a>;
絶対 URL を使用する必要がある場合は、いくつかのトリックを使用してください。 URL に追加されたセッション ID を手動で変更します。 HttpResponse クラスで applyAppPathModifier メソッドを呼び出すことができます。
<a runat="サーバー"
href=<% =Response.ApplyAppPathModifier("/code/page.aspx")%>; >;Click</a>;
applyAppPathModifier メソッドは、URL を表す文字列を使用し、セッション情報を埋め込んだ絶対 URL を返します。この手法は、たとえば HTTP ページから HTTPS ページにリダイレクトする必要がある場合に特に役立ちます。
概要
セッション状態は元々、開発者がセッション中にカスタム データを保存できるようにする辞書ベースの API として従来の ASP で導入されました。 ASP.NET では、セッション状態は、Cookie を使用しないセッション ID の保存と転送、およびセッション データが実際に保存される状態プロバイダーという 2 つの主な機能をサポートします。これら 2 つの新しい機能を実装するために、ASP.NET は HTTP モジュールを利用して、セッション状態と処理される要求のコンテキストの間のバインディングを制御します。
従来の ASP では、セッション状態を使用することは Cookie を使用することを意味します。 ASP.NET では Cookie のないアーキテクチャを使用できるため、これは当てはまりません。 HTTP モジュールの機能を利用すると、要求された URL を分解してセッション ID を含めてリダイレクトできます。次に、HTTP モジュールは URL からセッション ID を抽出し、それを使用して保存された状態を取得します。
セッションの物理状態は、インプロセス メモリ、アウトプロセス メモリ、SQL Server テーブルの 3 つの場所に保存できます。データはアプリケーションで使用する前にシリアル化/逆シリアル化する必要があります。 HTTP モジュールは、リクエストの開始時にプロバイダーからアプリケーションのメモリにセッション値をコピーします。リクエストが完了すると、変更されたステータスがプロバイダーに返されます。このデータ通信は、パフォーマンスにさまざまな程度の悪影響を及ぼしますが、信頼性と安定性を大幅に向上させ、WebファームおよびWebガーデンアーキテクチャのサポートを実装しやすくします。