Cutting Edge
シングル ページ インターフェイスと AJAX パターン
Dino Esposito
コードのダウンロード : :
CuttingEdge2008_05.exe
(203 KB)
Browse the Code Online

コンテンツ
現在の大多数の Web アプリケーション開発で使用されている開発パラダイムと異なり、AJAX は Web ソリューション設計にパラダイム シフトをもたらします。AJAX では、Web ベース システムの動作を示すいくつかの新しい原則および規則に依存するため、これらの原則や規則を実装するための新しいアルゴリズムが必要になります。
AJAX の主原則は、Web サーバーにプレーン データを送信し、よりプレーンなデータを受信することです。
2 つ目の AJAX 原則は、開発者が固有の操作を制御することにより、ホスト ブラウザとその単一ページ要求/応答手順をバイパスするということです。
3 つ目の AJAX 原則は、クライアント コードがサーバーから受信したプレーン データを使用してユーザー インターフェイスの更新を完全に制御するということです。
このコラムでは、部分的なレンダリングによる防衛的な AJAX の実装から完全に脱却する心構えを持っている開発者に相応しい基盤を提示します。部分的なレンダリングは AJAX の機能の一部を利用する手段ですが、Web フォーム アーキテクチャでは現在でも根強く使われています。AJAX パラダイムは新しいデザイン パターンを必要とする新しい原則に基づいています。
AJAX パラダイムの影響
ASP.NET の部分的なレンダリングは、従来の Web フォーム ポストバック モデルにおいては優れた付加機能です。つまり、部分的なレンダリングを使用したページのポストバック アーキテクチャとページ ライフサイクルは非 AJAX ページと同じだということです (図 1 を参照)。違いは、ブラウザの既定のアクションであるフォームの送信を行わずに、XMLHttpRequest を使用した HTTP 要求を行うクライアント側インターセプタにあります (図 2 を参照)。この方法により、ユーザーはページ全体を更新する必要がなくなり、開発者は新しいアーキテクチャやパターンの習得に時間をかける必要がありません。
図 1 従来のページ全体のポストバック処理 (画像を拡大するには、ここをクリックします)
図 2 AJAX XMLHttpRequest を使用した部分的なレンダリング (画像を拡大するには、ここをクリックします)
言うまでもなく、部分的なレンダリングは、現在のページのコンテキスト内のグラフィックにメリットをもたらします。ただし、アプリケーションを個々のページのコレクションを使用してデザインした場合、ページ間の遷移にはページ全体の読み込みが必要になります。部分的なレンダリングは、グリッドのページング、選択内容を変更した後のユーザー インターフェイスの調整、レコードの埋め込み先編集などのページ内ポストバックを置き換える場合に優れた方法です。
部分的なレンダリングはページ ポストバックの優れた一形式にすぎないため、Web フォーム モデルと同様の設計上の制限があります。たとえば、保持できる保留中の要求はブラウザ ウィンドウごとに 1 つのみです。フォームを送信して新しいページを取得するという Web アプリケーションの現在のモデルでは、この制限は大した問題にならないかもしれません。
ところが、AJAX に視野を広げて考えると、ユーザーが同時に複数のアクティビティを実行できることを期待するのが当たり前になってきます。部分的なレンダリングだけでは、ユーザーが同時に 2 つの非同期操作を実行し、両方とも完了させることはできません。
部分的なレンダリングでは、ビュー ステートの整合性を維持するため、処理できる要求は一度に 1 つのみに制限されており、このことは、このモデルに不可欠な条件になっています。これは、AJAX の最初の A が示す "非同期" の条件に反します。部分的なレンダリングで帯域外の JavaScript 駆動型ポストバックを行うことは可能ですが、処理されるのは一度に 1 つのみです。前の操作が完了する前に次の操作をトリガすると、新しい処理を開始するために保留中の操作が中断されます。この遅い者勝ちの規則をプログラムで早い者勝ちに変更して、現在の操作をアクティブな状態に維持し、新しい操作をシステムに保持することができますが、この場合も一度に処理される操作は 1 つのみです。
シングル ページ インターフェイス モデル
AJAX を最大限に活用するには、すべての機能、または少なくとも大部分の機能を単一ページに配置する必要があります。このモデルをシングル ページ インターフェイス (SPI) モデルと呼びます。SPI モデルでは、ブラウザと Web アプリケーションとの間のすべてのやりとりが 1 ページの範囲内で行われます。これは Web 上では画期的な方法ですが、Windows® およびデスクトップ環境では目新しいものではありません。結局、SPI モデルは固有のメイン ウィンドウを持つ Windows アプリケーションのようなものです。
SPI モデルのメイン ページは単独で読み込み、更新、および置換することが可能なビジュアル要素の組み合わせです (図 3 を参照)。この方法では、ユーザー操作が行われた後にページ全体を再読み込みする必要がありません。常に、アプリケーションの現在のステージに関連するビジュアル要素およびコンテンツのみが表示されます。他のすべての要素は非表示になりますが、アプリケーション フローで必要が生じれば、すぐに表示されます。
図 3 ページ内のシングル ページ インターフェイス要素 (画像を拡大するには、ここをクリックします)
SPI モデルでは、埋め込み先編集、状況依存のユーザー インターフェイス、即時のユーザー フィードバック プロンプト、非同期処理などの高度な対話型機能を使用できますが、パフォーマンスや応答性以上に重要な SPI モデルのメリットは、ユーザー エクスペリエンスの大幅な向上です。
SPI モデルにはこのように数多くのメリットがありますが、SPI モデルで新しいアプリケーションをデザインすることは容易ではなく、確立されたパターンやベスト プラクティスは存在しません。結局、多くの企業や場面に適した AJAX 導入の簡単な方法があります。定着した AJAX を使用する方法もありますが、この方法も簡単とはいえません。
純粋な AJAX アプリケーションを作成する場合、効果や特殊な動作を実装するための優れたユーザー インターフェイス ウィジェット ライブラリが必要です。また、標準的な World Wide Web Consortium (W3C) DOM を基本エンジンとして使用しながら、独自のアプリケーション固有モデルを定義することもできる機能豊富でカスタマイズ可能なドキュメント オブジェクト モデル (DOM) が必要です。最後に、ユーザー インターフェイスや分離コード スクリプトを簡単かつ効果的に開発するためのサーバーおよびクライアントのフレームワークも必要です。これらのすべての機能をデバッグし、テストするためのツールもあると便利です。
マイクロソフトなどのベンダがそのための各種ツールを提供しています。各種 UI ウィジェット ライブラリから選択することもできますし、固有のクライアント側オブジェクト モデルを定義するコントロールを製造しているベンダも存在します。特に有用なのは、Web フォームの代替機能として専用にデザインされ、SPI モデルを意識した高度な AJAX フレームワークです。
このような代替プログラミング モデルの一つに、ASP.NET 3.5 Extensions ライブラリの Model View Controller (MVC) フレームワークがあります。ただし、現在のフォームは AJAX と共有する部分が少なく、AJAX 機能を実装できないことはありませんが、SPI モデルに進化するようには設計されていないようです。この点については、やがて明らかになるでしょう。
SPI モデルのメイン ページは同じアプリケーションの HTTP エンドポイントを参照します。この場合リモート コードを実行しますが、ページ全体の再読み込みは行いません。また、HTML とスクリプトの両方を出力するコントロールを使用してユーザー インターフェイスを更新します。これらのコントロールは、必要な JavaScript コードの多くを生成するのに十分なほどインテリジェントにすることが可能です。たとえば、航空機の予約に使用するフォームに発着時刻または運賃という 2 つの検索パラメータを指定可能だとします。ユーザーがより低価格な航空運賃に関心がある場合、発着時刻のドロップダウン リストを表示する必要はありません。ユーザーが指定の時間に発着する必要がある場合、発着時刻を示す HTML を表示する必要があります。
この表示/非表示の方法は、わずかな JavaScript コードで簡単に実行できます。最近では、ページ開発者がこのコードの作成を担当します。ASP.NET AJAX Control Toolkit (
asp.net/AJAX/AjaxControlToolkit/Samples/CollapsiblePanel/CollapsiblePanel.aspx) の CollapsiblePanel コントロールなどのコントロールもこの処理に役立ちます。
シングル ページ インターフェイス モデルの短所
SPI モデルとこのモデルを実現する AJAX パラダイム全体は、対話型のユーザー エクスペリエンスを強化しますが、検索機能、履歴管理、アクセシビリティ、オフライン サポートなどの面で問題があります。何年もの間、Web ページの追跡には固定リンクが使用されてきました。検索エンジンの処理は、一連のキーワードを 1 つ以上の URL にマッピングするだけでした。このモデルは、Web アプリケーション内の各状態が 1 つのページと個別の URL に対応することを前提として機能します。
AJAX の SPI モデルでは、この前提は無効です。同一ページ内ですべての (または大部分の) 処理が行われる場合、異なる状態やサイト コンテンツを区別する URL の遷移が発生しません。そのため、コンテンツ (およびキーワード) を一意の URL に関連付けるのは簡単ではありません。SPI モデルのこの点が検索機能と履歴管理 ([戻る] ボタンや [進む] ボタンを使用する機能など) に影響を及ぼします。
ブラウザの履歴は最終的に廃れた概念になり、旧式の静的 Web モデルに密接にバインドされる可能性があります。それでも、ユーザーがこれらのボタンを使い慣れているという点を考慮する必要があり、これらのボタンを単純に無効にするという方法は選択の余地がありません。
アクセシビリティも AJAX アプリケーションの重要な問題点です。多くの一般的なスクリーン リーダーには、DOM スクリプトによって生成されたコンテンツに関する大きな問題があります。あらゆる形式の AJAX (部分的なレンダリングを含む) は、設計上、DOM スクリプトに大きく依存しています。そのため、他の手段でアクセシビリティに対処する必要があります。
Web Content Accessibility Guidelines (WCAG) に関する文書の Section 508 では、スクリプト言語を使用してコンテンツの表示やビジュアル要素の作成を行う場合、ページには必ず補助テクノロジで読み取ることが可能な代替機能テキストを提供することを勧告しています。<noscript> タグはこの勧告に準拠するために存在します。現在、AJAX フレームワークの大部分では、ページ内の動的な更新を行う際に <noscript> タグ内の静的情報を更新しません。
Accessible Rich Internet Application
問題には、AJAX アプリケーションに関する問題とスクリーン リーダーのテクノロジに関する問題の 2 点があります。一方、onclick、keypress、readystatechange などのクライアント イベントを認識するスクリーン リーダーがあります。スクリーン リーダーがこれらのイベントを認識していれば、少なくともアクセシビリティの第 1 層を多数の AJAX ベース アプリケーションに追加するには十分です。
ところが、スクリーン リーダーを DOM の初期ページ読み込みイベント以外で処理した場合、通常スクリーン リーダーは新しい情報を読み上げません。この場合、変更があったことをスクリーン リーダーに通知するいくつかの方法があります。最も有効な方法の 1 つは、更新された DOM ツリーのルートの tabindex を -1 に設定することです。この簡単な方法で、より広範な AJAX ソリューションにアクセシビリティが確保されます。
W3C で策定中の Accessible Rich Internet Applications (ARIA) と呼ばれる新しい標準を使用する方法もあります。この標準は、主にリーダー固有の HTML タグの拡張機能で構成されています。いくつかの一般的なクライアント側 AJAX ライブラリでは、既に ARIA の一部の機能をサポートしています。ただし、問題はアクセシビリティを実装するために AJAX 準拠の標準を使用できるかどうかということだけではありません。サーバー コントロールが実際に出力するコンテンツ (マークアップとスクリプト) にも問題があります。
オフライン アプリケーションについてはどうでしょうか。AJAX アプリケーションは今でも高度にインターネット ベースであるため、多くの開発者がオフライン AJAX アプリケーションは実現不可能だと考えています。でも、一言で言わせてもらえば、その考えはまったく間違っています。AJAX アプリケーションであるか、非 AJAX アプリケーションであるかを問わず、現在のほとんどすべての Web アプリケーションがインターネットまたはイントラネットをベースにしています。
ただし、非 AJAX アプリケーションは確実にオフラインで動作します。たとえば、履歴管理の場合、オフライン ナビゲーションの鍵はすべてブラウザにあります。従来の Web アプリケーションでは、各 HTTP 要求はブラウザによって管理されます。接続できない場合、HTTP 404 エラーを生成する前に、ブラウザはページのローカル キャッシュを検索します。
AJAX アプリケーションは、ブラウザ エンジンを使用して HTTP 要求を送信するのではなく、XMLHttpRequest オブジェクトを使用するという点で従来の Web アプリケーションとは異なります。AJAX アプリケーションでオフライン シナリオをサポートするには、ブラウザのキャッシュにアクセスする機能または閲覧中のページ固有のキャッシュを作成および管理する機能を XMLHttpRequest オブジェクトに付加するだけで済みます。この機能を備えた AJAX フレームワークも登場し始めています。ただし、この機能には JavaScript コード内からのディスク アクセスが伴うため、簡単な処理ではありません。
AJAX パターンの概要
次世代の Web ベース アプリケーションは AJAX に直結し、より一般的には、Rich Internet Application (RIA) に発展していきます。当初、この次世代への進化の主力は 3 つの主要アプリケーション カテゴリ (従来の HTML ベースのサイト、単一の Web ベース フロント エンドに複数のシステムを統合するために構築されたマッシュアップ、シック クライアント) でした。
従来の HTML ベース サイトでは、ユーザー インターフェイスの部分的な読み込み (部分的なレンダリング) が AJAX を実装する簡単な方法であり、この方法を使用すれば既存のコードやスキルへの影響も少なく済みます。
一方、マッシュアップの概念は必ずしも AJAX やユーザーの操作性の向上に適していません。マッシュアップはさまざまなソースからデータを収集し、一貫性のある連携したユーザー インターフェイスに結合する手段にすぎません。これは従来のサーバー間のシナリオでも実現可能です。ただし、AJAX を利用すれば、同じことをより単純明快で洗練された方法で実現できます。AJAX の観点から見ると、マッシュアップ アプリケーションには標準的なデータ シリアル化形式 (シンジケーション)、スクリプトでリモート サービスを呼び出すための軽量フレームワーク、更新可能な DOM が必要であり、場合によっては簡便なプログラミング モデルを使用したリッチ ビジュアル コントロールも必要です。
AJAX でシック クライアントを構築することは最大の難題です。シック クライアントは、分散エンタープライズ システムのフロント エンドや、おそらくは基幹業務アプリケーションのプレゼンテーション層の役割を果たすことが可能です。また、IT 部門が Web アプリケーションとして公開するスタンドアロン アプリケーションとしても利用できます。これらのアプリケーションには、インターネット上に公開されている場合でも、イントラネット内に限定されている場合でも、通常のデスクトップ ユーザー インターフェイスと同様のリッチネスと速度が必要です。
Windows 開発の場合と比べると、Web は対話性と応答性の点で遅れています。AJAX の登場により、格段に異なるモデルに進化するためのツール (および環境条件) がようやく手に入りました。ただし、重要なトレードオフがあります。従来の Web とその履歴、オフライン ナビゲーション、お気に入り、単一操作、ページ遷移、固定リンクのパラダイムに慣れているユーザーや開発者が無数に存在します。これに対して、AJAX には同時操作および単一の自動更新ユーザー インターフェイスのパラダイムがあります。この場合、AJAX モデルのユーザー操作には、単にブラウザの履歴機能やページ ナビゲーション機能を使用するだけではなく、完全な取り消しモデルが必要です。
SPI モデルでコードを記述するには、一連の新しいデザイン パターンが必要です。図 4 は一般的な AJAX パターンを示しています。ご覧のとおり、多くはユーザー インターフェイスの手法と配置に関するものが中心であり、Microsoft® AJAX クライアント ライブラリに既に実装されている AJAX の一般的なパターンや方法は一覧に含まれていません。たとえば、ASP.NET AJAX を使用する場合、AJAX スタブ、ブラウザ非依存 JavaScript モデル、または呼び出し状況の追跡モデルは不要です。これらの機能はすべて標準で提供されています。

Figure 4 一部の AJAX パターン
| パターン |
目的 |
| Browser-Side Templating (ブラウザ側テンプレート) |
このパターンは、リモート HTTP エンドポイントから取得したデータで動的に具体化する HTML テンプレートを使用することを示します。このパターンでは、実行中に要求されるたびにデータの HTML レイアウトを再生成するのではなく、開発者が固有のテンプレート層を設定します。このパターンは HTML Message パターンの代替になります。 |
| Cross-Domain Proxy (ドメイン間プロキシ) |
このパターンは、アクセス可能な公開サービスへのサーバー間接続を処理し、クライアントにデータを返送します。クライアント ブラウザから AJAX アプリケーションをページのドメインの外部の URL に接続することはできません。ただし、同じドメイン内のローカル プロキシで簡単にどこからでもデータを取得し、呼び出し元に返送することができます。 |
| Heartbeat (ハートビート) |
多くの AJAX アプリケーションは、ポストバックすることなくクライアント上の多くの処理を実行する可能性があるため、特定のクライアントがアクティブな状態であることをサーバーに通知することが必要になる場合があります。このパターンは、クライアント アプリケーションが定期的に "ハートビート" メッセージをアップロードして、アプリケーションが読み込まれ、ブラウザで動作している状態であることを知らせることを示します。 |
| HTML Message (HTML メッセージ) |
リモート HTTP エンドポイントは、通常、既存の DOM に統合するための JavaScript Object Notation (JSON) データをクライアントに返します。このタスクを実行するには JavaScript が必要です。ただし、クライアント コードが特に複雑な場合や、パフォーマンスを重視する場合には、HTML (データおよびレイアウト) をプレーン データではなくサーバーから取得した方が好都合なことがあります。 |
| Microlink (ミクロリンク) |
AJAX は主に同じページ内の多くの操作の実行に使用されます。外部コンテンツ、つまり、従来の Web アプリケーションで言えば、別のページに移動するコンテンツを参照するには、ページ内ハイパーリンクの一種であるミクロリンクが必要です。ミクロリンクは、サーバー呼び出しによって取得したマークアップを参照し、ページに挿入します。ミクロリンクには HTTP エンドポイントまたは JavaScript コマンド オブジェクトのメソッドを使用できます。 |
| On-Demand JavaScript (オンデマンド JavaScript) |
このパターンは、データ アクセス層で一般に使われるレイジー読み込みパターンに相当する JavaScript パターンです。必要なすべての JavaScript をページの初期化時にダウンロードすると、パフォーマンスに影響し、プロセス全体が低速になる可能性があります。要求ごとに JavaScript ファイルを読み込むようにすることで、機能を損なうことなくページの読み込み速度を高めることができます。 |
| Page Arrangement (ページ配置) |
アプリケーションの多くの操作は同一ページ内で行われるため、コンテキストが変更されるたびにページのコンテンツを更新して新しい情報を表示する必要があります。このパターンは、開発者が DOM を使用して要素の追加/削除や表示/非表示を行い、状態の遷移を反映することを示します。 |
| Periodic Refresh (定期的更新) |
ブラウザが定期的に要求をスケジュールして最新の情報を取得し、ユーザー インターフェイスを更新します。 |
| Popup (ポップアップ) |
このパターンは、Windows ダイアログ ボックスのモーダル/モードレスの Web バージョンです。ポップアップは既存のコンテンツの前に表示される HTML コンテンツで構成され、ユーザーが破棄するまでの比較的短時間だけ表示されます。 |
| Predictive Fetch (処理の先読み) |
このパターンは、最も可能性の高いユーザー操作を予測し、必要なデータを事前に取り出すことを示します。このパターンはあくまで推測であり、間違っている可能性があるため、実装にはコストが伴います。このパターンは体感的なパフォーマンスの向上には有効ですが、実装が不適切であったり、サーバー帯域幅を大量に使用するため実装に適さない状況では、パフォーマンスが低下する可能性があります。 |
| Progress Indicator (進行状況の表示) |
このパターンは、サーバー処理の進行状況の監視に使われます。そのしくみは、サーバー処理が固有の進行状況を共有の場所に書き込み、クライアント側の監視サービスが進行状況の更新を読み取るようになっています。 |
| Submission Throttling (送信回数の削減) |
AJAX の潜在的な短所の 1 つは、単位時間内にサーバーに過剰な数の要求が生成される可能性があることです。この場合は紛れもなくスケーラビリティの問題が生じます。このパターンは、開発者がタイマーを使用して定期的にデータをサーバーおよびローカル キャッシュにアップロードするか、キューにアップロードして要求を蓄積することを示します。 |
| Timeout (タイムアウト) |
クライアントからストリーミングや定期的な更新などの高負荷の処理が実行された場合、接続中の各クライアントが実際にアプリケーションを使用しているかどうかを確認するという問題があります。このパターンは、高負荷の処理をタイムアウトし、ユーザーが明示的に要求した場合にのみ再開することを示します。 |
| Unique URL (一意な URL) |
このパターンでは、一般に異なる状態を反映するアプリケーションの異なる部分に個別に URL を割り当てることができます。このパターンは、一般に AJAX アプリケーションの履歴のサポートに使われます。 |
| Virtual Workspace (仮想ワークスペース) |
サーバーは要求にできるだけ迅速に応答する必要がありますが、帯域幅の制約があるため、必ずしもすべてのデータを返すことができるとは限りません。このパターンは、すべてのデータが使用可能であることを通知する仮想ユーザー インターフェイスを構築し、実際にはクライアント上に一部のデータのみを提供することを示します。データをオンデマンドでダウンロードし、ローカルにキャッシュする役割はアプリケーションが果たします。 |
図 4 に記載されているパターンおよび一般的な AJAX パターンは、デザイン パターンというよりも参照パターンであることにも注意が必要です。AJAX パターンは操作の一般的な方法を示していますが、必ずしもデザインの問題を扱っているわけではありません。
図 4 では、各パターンの要点を示しました。以降では、これらのパターンの一部について詳しく説明します。今後のコラムで、その他の重要なパターンの効果について説明し、実用的な実装例を示していきます (AJAX パターンの詳細については、
ajaxpatterns.org を参照してください)。
Unique URL パターン
URL は Web の重要な要素です。ユーザーは今後参照するために URL のお気に入りを保存し、新しいコンテンツ エクスペリエンスの URL を辿り、URL を使用して以前の状態に戻ります。AJAX と SPI モデルを使用すると、アプリケーションで単一 URL 内からさまざまなタスクを実行できます。このことにより、アプリケーションの個々の状態は個別の URL で識別されるという Web エクスペリエンスの要点が損なわれる懸念が生じます。
ユーザーがナビゲーションすると、ブラウザは固有の URL キャッシュを作成します。ただし、AJAX を使用した場合、多くの操作はブラウザを介さず、[戻る] メニューおよび [進む] メニューの起動元になる閲覧された URL のリストにキャッシュされません。また、クライアント ブラウザは JavaScript コードのプログラミング モデルを公開しないため、URL はリストに追加されません。ブラウザ オブジェクト モデルは、既存のリスト内を前後に移動するメソッドを提供するだけの役割を果たします。
Unique URL パターンは、アプリケーションの重要な各状態に一意のわかりやすい URL を割り当てます。たとえば、ユーザーが AJAX ページ内をクリックして値を編集したら、同じページ内で XMLHttpRequest を使用した場合でも、新しい URL がブラウザのキャッシュに追加されるようにする必要があります。
次の JavaScript を使用して、ページを再読み込みしないで URL を変更します。
window.location.hash = stateInfo;
このコードにより、次のように # がプリフィックスとして付加されたフラグメントが URL に追加されます。
http://www.contoso.com/shopping.aspx#edit-1234
このパターンを使用すると、一定の AJAX 操作を起動し、アプリケーションの状態の変更をブラウザで追跡できるようになったとき、URL は実際に変更されます。
ただし、URL をキャプチャするだけでは終わりません。ブラウザにハッシュ ベースの URL を指定すると、メイン URL が読み込まれた後、ハッシュ名でページ フラグメントが検索されます。AJAX のコンテキストでは、ハッシュ名は実際のページ フラグメントではなく、現在の状態を表すアプリケーション固有の情報を示します。たとえば、edit-1234 で、1234 という ID のアイテムを編集していることを示すことができます。実際の形式は完全にユーザーが指定できます。
適切なフラグメントが見つからない場合、ブラウザは URL ハッシュを無視します。そのため、ユーザーのページは読み込まれますが、アプリケーションの状態は予期される状態であるとは限りません。そこでもう一つ工夫が必要です。ページの onload イベントをインターセプトし、URL を解析し、ハッシュを抽出して、ページを目的の状態に設定するために必要な次のような JavaScript コードを実行します。
window.onload = function() {
checkAndParseURL();
}
checkAndParseURL() {
var state = window.location.hash;
restorePage(state);
}
同様の方法が ASP.NET 3.5 Extensions での履歴のサポートに実装されています。詳細については、quickstarts.asp.net/3-5-extensions/ajax を参照してください。ASP.NET 3.5 Extensions のソリューションはフレームワークに完全に統合されています。その結果が ScriptManager コントロールに追加された新しいプロパティおよびイベントです。これも結局は Unique URL パターンの実装です。
また、URL のハッシュに基づいた方法は Internet Explorer
® では使用できないことに注意してください。これは、Internet Explorer ではインライン フレーム以外の URL のハッシュの変更が認識されないためです。フラグメントのナビゲーションの処理方法にはブラウザごとに特有の癖があります (詳細については、「
weblogs.asp.net/bleroy/archive/2007/09/07/how-to-build-a-cross-browser-history-management-system.aspx」を参照してください)。ASP.NET 3.5 Extensions のソリューションはこれらの相違に対処し、完全なブラウザの互換性を確保します。
Timeout パターン
AJAX の最大のメリットの 1 つは、リアルタイム ページ更新を実装可能だということです。ただし、ライブ更新は、使い方を誤るとアプリケーションを重大な危険にさらす可能性があります。数秒ごとにサーバーをポーリングしてコンテンツを更新するライブ ページをユーザーが表示するシナリオを考えてみましょう。ユーザーはブラウザを数時間シャットダウンしないとします。そのため、ページは要求の送信を続け、サーバーに対して相当に無駄な負荷をかけます。
クライアント セッションがタイムアウトしたかどうかはどのように判断したらよいでしょうか。サーバー上ではセッションのタイムアウトが発生しますが、AJAX ではクライアント セッションも問題になります。クライアント セッションの終了を検出するには、一定時間にクリックやタップなどのユーザー操作が発生したかどうかを確認する必要があります。キーボードおよびマウス操作の監視は処理が重くなる可能性があります。タイマーを使用した、より単純で軽量な方法の方が一般に効果的です。
タイマーに基づいてセッションの終了を検出するには、一定秒数 (またはより一般的には一定分数) の経過後にタイムアウトして継続中のタスクを停止し、警告メッセージをポップアップ表示するクライアント タイマーを設定します。ユーザーがプロンプトに応答すると、処理は通常どおりに再開します。
図 5 は、Timeout パターンの要点を示す JavaScript を示しています。サンプル ページにはクロックが埋め込まれています。クロックは、次のように、Timer コントロールによって定期的に更新される UpdatePanel 内の Label コントロールを使用して取得します。

Figure 5 クライアント セッション タイムアウトの実装
<script type="text/javascript">
var timer = null;
function pageLoad()
{
if (timer === null)
{
timer = new Samples.TaskTimer(5000, stopTask);
timer.start();
}
}
function pageUnload()
{
if (timer != null)
timer.stop();
}
function stopTask()
{
// Stop the clock
var clock = $find("<%= Timer1.ClientID%>");
clock._stopTimer();
AskIfTheUserWantsToContinue();
}
function AskIfTheUserWantsToContinue()
{
// Ask if the user wants to continue
var answer = window.confirm(
"Is it OK to continue with the clock?");
if (answer)
{
// Restart the task
var clock = $find("<%= Timer1.ClientID%>");
clock._startTimer();
// Restart our own timeout engine
if (timer !== null)
timer.start();
return;
}
}
</script>
protected void Timer1_Tick(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToLongTimeString();
}
このクロックは、サーバーが要求でいっぱいになる可能性のある重負荷のタスクを示しています。目的は、クロックを続行するかどうかをユーザーに定期的に問い合わせるタイマーを設定することです。タイムアウト コードを実行すると、まずクロックが停止し、次にメッセージ ボックスが表示されます。ユーザーの応答に基づいてクロックが再開します。
このコードでは、$find 関数を使用して ASP.NET AJAX コンポーネントを検索します。例では、このコンポーネントは ASP.NET の Timer サーバー コントロールのクライアント オブジェクト モデルです。図 6 は、続行するかどうかをユーザーに確認するポップアップ画面を操作するページを示します。
図 6 ユーザーに続行するかどうかを確認する (画像を拡大するには、ここをクリックします)
ご意見やご質問は、こちらまで英語でお送りください。 cutting@microsoft.com.
Dino Esposito は、『Programming ASP.NET 3.5 Core References』の著者です。Dino はイタリアに在住し、世界各国で開催される業界のイベントで頻繁に講演しています。ブログは
weblogs.asp.net/despos で読むことができます。