.NETエンタープライズ
Webアプリケーション開発技術大全

Sessionオブジェクト

マイクロソフト コンサルティング本部 赤間 信幸
2004/07/15

B. サイズ肥大化に対する事前予防策

 このように、Sessionデータのサイズに関してはかなり気を使ったアプリケーション設計を行う必要があるが、実際の開発現場では巨大データをSessionオブジェクトに気軽に格納してしまっているケースが多い。このため何らかのシステマティックな方法でチェックをかけ、開発中にこうした設計ミスに気付き、これを取り除けるようにしておくことが望ましい。典型的なテクニックとし ては以下の2つがある(図7)。

図7 Sessionオブジェクトの肥大化を防ぐ主な2つの方法

・ データアクセス用のユーティリティコンポーネントに、取得データ行数に関する共通チェックロジックを組み込んでおく。
  ・ 例えばDAAB※11のようなデータアクセス用ユーティリティコンポーネントに改造を加え、500件を超えるデータ取得が行われた場合にはイベントログなどに警告を出力するようにしておく。
 
・ global.asaxの中に、Sessionデータサイズをチェックする共通チェックロジックを組み込んでおく。
  ・ 各ページの処理が終わった直後に、共通的にSessionデータのサイズをチェックする。
  ・ 例えば100KBを超えるデータ格納が行われていた場合には、イベントログなどに警告を出力するようにしておく。
 
※11 Data Access Application Blockの略。patterns & practicesから提供されている汎用アプリケーション部品の1つで、データアクセスコードの記述(特にコネクションリークに対処するためのコードの記述)を簡素化することかできる。
http://msdn.microsoft.com/library/en-us/dnbda/html/daab-rm.asp

 ここでは後者に関して解説を行う。Visual Studio .NETを用いてWebアプリケーションを作成すると、そのプロジェクト中にglobal.asaxと名づけられたファイルが作成される。global.asaxは、当該Webアプリケーション全体に対する各種の共通処理ロジックを記述することができるモジュールになっている※12。これを利用すると、すべてのWebページに対して共通的なチェックをかけることができるようになる。

※12 global.asaxをより詳しく理解するためにはHTTPパイプライン処理について正しく理解する必要があるが、これについては「第3章 ASP.NETランタイムの詳細動作」にて解説する。ここでは簡単に、共通処理を記述することが可能なモジュールだと考えておけばよい。

 具体的には、このglobal.asaxのコードビハインドファイルであるglobal.asax.cs(またはglobal.asax.vb)ファイルを開き、リスト3のような関数を追加する。このようにすると、どのWebページを実行しても、その処理終了直後にこのチェック処理が呼び出されるようになる。

C#の場合

protected void Application_PostRequestHandlerExecute(Object sender, EventArgs e)
{
  #if DEBUG
  long size = WebUtil.CalculateSessionSize(); // 前述のロジックを利用
  if (size > 100000)
  {
    EventLog el = new EventLog();
    el.Source = "Application";
    el.WriteEntry("Sessionに巨大データが含まれています。"
      + "サイズ=" + size.ToString() + " "
      + "ページ=" + HttpContext.Current.Request.Url.ToString(),
      EventLogEntryType.Warning);
  }
  #endif
}
VB.NETの場合

Sub Application_PostRequestHandlerExecute(ByVal sender As Object, ByVal e As EventArgs)
  #If Debug Then
  Dim size As Long = WebUtil.CalculateSessionSize() ' 前述のロジックを利用
  If (size > 100000) Then
    Dim el As New EventLog()
    el.Source = "Application"
    el.WriteEntry("Sessionに巨大データが含まれています。" _
      + "サイズ=" + size.ToString() + " " _
      + "ページ=" + HttpContext.Current.Request.Url.ToString(), _
      EventLogEntryType.Warning)
  End If
  #End If
End Sub
リスト3 global.asax.csまたはglobal.asax.vbファイルに追加する共通チェックの例

C. 巨大なページング制御

 Sessionデータサイズ問題は、巨大なデータをページング制御しようとした場合によく発生する。

図8 検索条件にヒットした件数が多すぎて表示しきれない例

 図8のようなデータの検索・一覧表示アプリケーションにおいて、数千〜数万のレコードを持つDataSetをページング制御しようとすると、先のSessionデータサイズ問題にぶつかることになる。

 とはいえ、このようなアプリケーションは、Sessionデータサイズの問題もさることながら、業務アプリケーションとしても使い勝手が良いとは言えないだろう。そもそもWebユーザインタフェースにおいて巨大データをページング操作させるのは、UI設計としてのセンスにも欠けているため、業務的な観点からUI設計そのものを見直した方がよい。具体的には、以下のような見直し作業を行うとよい※13

※13 もしどうしても巨大データのページングが必須である場合には、巨大データをデータベース上のカスタムテーブルに一時的に保存し、ページングのつど動的にWHERE句を組み立て、該当ページ部分のデータだけをカスタムテーブルから逐次取得するように作る、などの工夫を行う必要がある。
 
・ 指定できる検索条件の追加あるいは見直し
  ・ あ行、か行、さ行……といったインデックス指定による絞込み条件の追加
  ・ 年別や月別、あるいは直近3か月といった範囲指定も、非常に有効なことが多い
  ・ 条件の組み合わせにより、簡単に数100件程度にデータを絞り込めるようにしておくとよい
 
・ 上限件数を超えた場合の検索処理の強制中断
  ・ 実行するSQL文にTOP句を付与し、一定件数以上のデータをデータベースから取得しないようにする。
    ◇ SELECT TOP 301 OrderID, EmployeeID, OrderDate, RequiredDate FROMOrders WHERE OrderDate > 1997-07-01 AND CustomerID='VINET' ORDER BYOrderDate DESC
    ◇ このようにしておくと、仮に302件以上が検索条件にヒットした場合でも、上位301件分しかデータが取得されない。
  ・ 設定された上限件数以上のデータがヒットした場合には、以下のような処理を行う。
    ◇ 上限件数までの検索結果分については画面に表示する。
    ◇ 場合によっては再度COUNT()クエリを発行し、ヒット件数のみを画面に表示してもよい。
    ◇ エンドユーザに対しては、検索条件追加をお願いするメッセージを表示する。

 いずれにしても、以下の2点についてはよく押さえておいて頂きたい。

  • 巨大データをそのままSessionオブジェクトに格納してページング制御を行うことはできない

  • ページング制御が必要となる箇所は、検索条件の工夫など、設計上何らかの工夫が必要になることが多い。

D. Sessionデータの有効時間と削除処理

 Webサーバ側ではクライアントがブラウザを閉じたこと(あるいは障害を起こしたこと)を検知できない。このため、Sessionデータを無制限に保持し続けると、サーバ側リソースが無尽蔵に消費されてしまう。この問題を避けるため、Sessionオブジェクトにはデフォルトで20分というタイムアウト時間が設けられており、20分間に渡ってブラウザからリクエストがなかった場合には、Webサーバ上の当該セッションのデータが消去されるようになっている。

 このタイムアウト時間は、後述するセッションハイジャックのリスクを緩和するためには短くした方がよいが、あまりに短くしすぎると(エンドユーザのブラウザ上での操作中に)簡単にセッションタイムアウトを起こしてしまい、使い勝手の悪いWebアプリケーションとなってしまう。このため、変更する場合には、セキュリティ要件と使い勝手のトレードオフをうまくバランスするように設定する必要がある。

 また、Sessionに保存したデータが不要になった場合には、明示的にRemove()処理を行う必要がある。Sessionにデータを追加保存し続けると、そのサイズは膨らむ一方であるため、一連の画面遷移の最後で明示的にRemove()し、不要なデータはこまめに削除するようにする。

 ログアウトのページなどではSession.Abandon()メソッドなどを呼び出し、明示的にセッションを破棄するとよいだろう。

 Sessionに格納するデータサイズに関連する注意事項は以上である。引き続き、セッションとパーソナライズ、認証の違いについて解説する。


 INDEX
  .NETエンタープライズWebアプリケーション 開発技術大全
  Sessionオブジェクト
    1.Sessionオブジェクトに格納可能なデータ
    2.Sessionデータの保存場所と耐障害性(ステートサービスとステートデータベース)
    3.Sessionデータのサイズ(1)
  4.Sessionデータのサイズ(2)
    5.パーソナライズ、セッション、認証済みアクセスの違いと使い分け
    6.画面遷移制御とアプリケーションコントローラ(1)
    7.画面遷移制御とアプリケーションコントローラ(2)
 
インデックス・ページヘ  「.NETエンタープライズWebアプリケーション開発技術大全」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間