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

ポストバック処理

マイクロソフト コンサルティング本部 赤間 信幸
2004/06/17
Page1 Page2 Page3 Page4

2 ポストバック処理の詳細なランタイム動作

 ここまでポストバック機能によってHTTPの低水準の通信内容を意識せずにWebアプリケーションを開発していくことが可能になることを説明したが、やはり依然としてASP.NETがHTTP通信メカニズムの上で動作するものであることには変わりがない。このため、いわゆる「Webフォーム」と呼ばれている.aspxのプログラムもWindowsアプリケーションのフォームとは大きく異なる挙動を示す部分がある。特にVisual Studio .NETを使った場合、見た目こそVisual Basic 6.0などのフォームに似た開発スタイルが可能になるものの、同じ感覚でアプリケーションを開発してしまうとうまく動作しないアプリケーションになりがちである。

 このような事態を避けるためにも、もう少し詳しくポストバック処理のランタイム動作を理解しておくとよい。ランタイム動作を正しく理解することにより、ポストバック処理をベースとしたWebアプリケーションの「クセ」も理解できるようになる。

 ポストバックのランタイム動作を理解するためのキーポイントは以下の2点である。

  • ページインスタンスの破棄と再生成
  • ViewStateを用いたイベント処理

 順を追って解説しよう。

2.1 ページインスタンスの破棄と再生成

 先の図4に掲載したポストバックの処理シーケンスをもう一度よく見て頂きたい。この一連の処理シーケンスにおいて、初回リクエストとポストバック処理の際ではWebサーバ上で使われているページインスタンスが異なっている(図5)。

 敢えて初回リクエスト時に作成したインスタンスを破棄してポストバック処理にページインスタンスを再生成するのは、Webサーバのスケーラビリティを確保するためである※5

※5 ここで言うスケーラビリティ(拡張性)とは、1台のWebサーバにおいてどの程度の数のクライアントをサポートできるかを示すものである。

 通常、初回リクエスト終了後からポストバックまでの間にはブラウザ上でエンドユーザによる操作が行われるため、数秒から数十秒の時間が開くことになる。この期間中Webサーバ上でページインスタンスを保有し続けようとすると、Webサーバ上にはエンドユーザと同じ数だけのメモリリソースが必要となるため非効率的である。しかしASP.NETではエンドユーザがブラウザ上で操作を行っている間はページインスタンスを破棄するように動作する。このためサーバ上に必要なリソースは、実際にWebサーバにリクエストを「今、その瞬間に」送信しているユーザの分だけで済む。一般にその数は実際のエンドユーザ数に比べると遥かに少ないため、Webサーバのリソースが大幅に有効活用されることになる。

図5 インスタンスを捨てない場合とASP.NETポストバックの場合の比較

 このようなスケーラビリティを意識した内部設計はWebシステムにおいては極めて重要であり、ASP.NETはまさにそれを踏襲した内部設計になっているわけだが、ユーザアプリケーションを開発する我々の観点から考えると厄介な点もある。それは、初回リクエストとポストバックの際には異なるページインスタンスが利用されるため、.aspx内のデータが毎回初期化されてしまうという点である。このため、ポストバックにまたがってデータを保有し続けたい場合には、ページ内のデータ変数を用いてはならない。そのようなデータは後述するSessionやViewStateなどに退避しておく必要がある※6

※6 なおこのような議論を行う際に、ポストバックにまたがって同じページインスタンスを利用するため、ページインスタンスをシリアライズしてディスクなどに退避させる(デアクティベートさせる)方法の方がよいのではないかと考える人も稀にいるが、これは誤りである。そのようなデアクティベート/アクティベートの処理はオーバヘッドが大きく、性能を犠牲にすることになる。またWebサーバがクラスタリングされている場合にはデアクティベートしたサーバとアクティベートするサーバが異なる場合があるため非常に厄介である。同様の議論はEJB(SessionBean)のデアクティベートやサービスコンポーネントのJIT(Just-in-timeアクティベーション)の議論についても言える。詳細については今秋発行予定の第5巻「トランザクション設計編」を参照して頂きたい。

2.2 ViewStateを用いたイベント処理

 さてポストバックが行われた場合、サーバ側では送信されてきたデータを解析してブラウザ上で行われた操作を割り出し、登録されているイベントハンドラを呼び出す。しかし厳密に考えてみると、Webサーバ上においてブラウザ上で行われた操作を正しく把握することは容易ではない(図6)。Webサーバとブラウザクライアント間ではHTTPによる通信が行われているため、Webサーバがクライアントブラウザ上でのキーボード操作を直接的に把握できるわけではないからである。Webサーバ上においてブラウザ上で行われた操作を正しく把握するためには、その操作「前」のデータと、操作「後」のデータとの突合せ作業が必要になる。

図6 Webサーバ側ではブラウザ側で行われた操作を正しく把握することは容易ではない

 ところがこの突合せ作業は容易ではない。ブラウザからのHTTPデータ送信では操作「後」のデータしか送られない。またWebサーバ上のページインスタンスは(スケーラビリティ確保のために)毎回初期化される。このため操作「前」のデータとの突合せが容易にはできないのである。

 この問題を解決しているのが、ASP.NETフレームワークのViewStateと呼ばれる仕組みである。ViewStateとはその名の通り、WebコントロールやHTMLコントロールに関する表示状態(表示テキストの内容など)の情報を保存しておく仕組みであり、図6ののデータ送信の際にクライアントブラウザへ隠し情報として送信されているものである。

 リスト5のHTMLコードはでクライアントへ送信されてきたHTMLデータであるが、下線で示した部分がViewStateと呼ばれる情報である※7。この情報はブラウザ画面上には表示されない隠し情報となっており、ボタン押下によるWebサーバへのデータ送出時()にユーザの入力データとまとめて送信される。

※7 このViewState情報を含んだ隠しINPUTタグはForm HTMLコントロールから出力されている。このためポストバックを利用する際にはWebコントロールを囲むFORMタグにrunat="server"を付与することが必須となる。
 
HTMLブロック

<HTML><BODY>
  <form name="_ctl0" method="post" action="HelloWorld2.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE"
value="dDwtMTM3NjQ2NjY2NTs7Pvrbbd7RpznOyhC6sTgCgtoSqoUU" />

    <input name="MyTextBox" type="text" id="MyTextBox" />
    <input type="submit" name="MyButton" value="表示" id="MyButton" />
    <HR>
    <span id="MyLabel"></span>
  </form>
</BODY></HTML>
リスト5 ViewSateを含んだHTMLコードの例

 このViewStateのデータの中にはブラウザ上でのデータ入力操作前の状態(表示状態)がエンコード保存されており※8、このデータはポストバック時にブラウザからWebサーバへ再送される。Webサーバ側では送信されてきたViewStateの内容と最新データとの突合せを行う。これによってクライアントブラウザ上で行われた作業を把握し、対応するイベントハンドラを呼び出す仕組みになっている。この一連の詳細な処理フローを図7に整理する。

※8 デフォルト状態では暗号化はされていない。暗号化の方法などについては本シリーズ第3巻「ASP.NET応用編」にて解説する。

A. 最初のリクエスト(シーケンス

 最初にhttp://localhost/HelloWorld2.aspx へリクエストが行われると、Webサーバ側では新規にページインスタンスが作成されて処理が行われる。ページインスタンス内ではWeb UIコントロールツリーが生成され、そこからHTMLコードが出力され、クライアントブラウザへと返される。

 でクライアントにHTMLコードが返されるとサーバ側のページインスタンスは破棄されていったん消え去るが、このときの表示内容はViewStateという名の隠しタグを用いてHTMLコード中に出力されている。

図7 ASP.NETフレームワークのViewStateの処理フロー

B. ブラウザからのポストバック(シーケンス

 エンドユーザがブラウザ上でデータを入力し、ボタンを押下するとWebサーバへデータが送信される。この際、サーバにはエンドユーザが入力した最新データに加えてViewState情報がまとめてサーバに送信される。

C. サーバ側でのイベントハンドラ呼び出し(シーケンス

 ASP.NETランタイムはページインスタンスを新規に生成し、まず送信されてきたViewState情報(の状態)を復元する。その後、送信された最新データを適用し、Page_Load()メソッドを呼び出す。

 その後、ViewStateと最新状態とのデータのずれをチェックし、ブラウザ上で行われた操作に対応するイベントハンドラを順次呼び出す。

 最終的には、イベントハンドラにより加工されたWeb UIコントロールツリーからHTMLコードを出力させ、クライアントブラウザへと送り返す。

 なお、厳密にはViewStateと最新状態とのデータのずれのチェックは二段階で行われている。まず、内容が変更されたWebコントロールに対してOnTextChangedなどのイベントハンドラを呼び出す(このような変更に基づくイベントハンドラをChange系イベントハンドラと呼ぶ)。続いて、押されたボタンがチェックされ、OnClickなどのイベントハンドラが呼び出される(このようなイベントハンドラをAction系イベントハンドラと呼ぶ)。

 以上の処理フローからポストバック機能の本質を以下のようにまとめることができる。すなわちポストバック機能とは、ViewStateを利用してブラウザ上で行われた操作をサーバ側で「再現」し、対応するメソッド(イベントハンドラ)を自動的に呼び出す機能である。

 HTTP通信を直接的に操作する従来型のASPやJSPのアプリケーション開発手法でこのような考え方に基づくプログラミングスタイルを実現するためには独自の制御メカニズムを作り込む必要があった。しかしASP.NETフレームワークではViewStateなどに関連する一連の複雑な作業がすべて自動的に行われるため、アプリケーション開発が大幅に容易化されるのである。


 INDEX
  .NETエンタープライズWebアプリケーション 開発技術大全
  ポストバック処理
    1.ポストバック処理の概要
    2.ポストバックの処理シーケンス
  3.ポストバック処理の詳細なランタイム動作
    4.ポストバックの注意すべき点と設計のスタイル

インデックス・ページヘ  「.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 記事ランキング

本日 月間