Cutting Edge
HTML Message パターン
Dino Esposito
真の AJAX アーキテクチャの特徴は、プレゼンテーション層とサービス層が明確に分けられていることです。先月号で説明したように、AJAX フロント エンドと AJAX バック エンド間の明示的なコントラクトの存在により、プログラミングの可能性は広がりますが、アーキテクチャに関する数多くの疑問も生じます (
msdn.microsoft.com/magazine/cc546561 を参照)。先月は、クライアント側のデータ バインドとテンプレート、およびブラウザ側テンプレート (BST) パターンの実装について説明しました。また、Web クライアントのユーザー インターフェイスをレンダリングするための代替モデルとして、HTML Message (HTM) パターンについても簡単に紹介しました。今月号では、BST の拡張された実装について説明し、それを HTM ソリューションと比較します。
AJAX サービス層
ここでは、一般的な AJAX プレゼンテーション層のサーバー側の部分のことを AJAX サービス層と呼び、通常、標準的な多階層アーキテクチャのプレゼンテーション層と中間層の間にあるコンタクト ポイントのことを表すサービス層とは区別します。図 1 にこのモデルを示します。
図 1 AJAX フロント エンドを含む一般的な多階層システム (クリックすると拡大画像が表示されます)
AJAX サービス層とクライアント フロント エンド間の通信は、HTTP エンドポイントを通じて行われます。これらのエンドポイントは、Windows® Communication Foundation (WCF) サービスにより公開され、クライアント ページに埋め込まれた JavaScript プロキシ クラスによって呼び出されます。特に ASP.NET AJAX がリファレンス プラットフォームの場合、AJAX サービス層でのサービスの設計と利用はそれほど問題にはなりません。問題が生じるのは、ユーザー インターフェイスを作成または更新するときです。
特に、JavaScript ベースのデータ バインドやテンプレートなど、クライアント上のデータを効果的に操作するための強力なツールが必要になります。このコンテキストでは、ASP.NET の部分的なレンダリングは、実際のアーキテクチャのシフトを伴わない短期的なソリューションにすぎません。ただし、ASP.NET の部分的なレンダリングを利用することで、プログラムによるユーザー インターフェイスの生成を行わずに済みます。部分的なレンダリングにより、ビュー ステートとサーバー ページ ライフサイクルは維持されます。また、コントロールやプロパティを使用し、宣言でユーザー インターフェイスを設計できるようになります。
このようなモデルは、比較的シンプルな Web サイトには最適かもしれませんが、AJAX フロント エンドが多階層サービス指向システムの最上位層となるようなエンタープライズ シナリオにおいて効果的かどうかは疑問です。図 1 に示すように、AJAX サービス層は JavaScript のフロント エンドと一連のビジネス サービスの間にある中間層です。この層は、Customer to Business (C2B) シナリオにおけるコア サービスを保護するセキュリティ バリアを追加し、JavaScript オブジェクトとの間のデータを管理することで、2 つの層の間のインピーダンス不整合を解消します。
AJAX アーキテクチャの AJAX サービス層が果たす重要な役割のため、アーキテクトや開発者は、生データ (コア サービスによって返され、AJAX サービス層で処理されるデータ) に基づく HTML ユーザー インターフェイスに対処するという問題を避けて通ることができなくなります。では、生の JavaScript データに基づいてブラウザ ユーザー インターフェイスを動的に作成、更新するにはどうすればよいのでしょうか。
HTML UI の一般的なパターン
長年にわたる ASP.NET サーバー コントロールを利用した作業のために、HTML ユーザー インターフェイスを構築するうえで何が本当に必要なのかがあいまいになっている可能性があります。カスタム コントロールの開発経験のある方は覚えておられるでしょうが、それは結局のところ、HTML マークアップをバッファに累積し、それを応答ストリームに出力することです。この一般的なパターン以外の方法はありません。付加的な作業は、エラーの発生を抑え、管理しやすくするためだけに行います。そのため、HTML が累積されるバッファは、HTML リテラルを記述するプレーンなメモリ ストリーム、またはより高度なコンポーネントの階層 (各コンポーネントで HTML のチャンクを抽出) です。
従来の ASP.NET では、Web ページの応答は再帰的にアクセスされるコントロール ツリーを構成することで取得されます。ツリーの各メンバは、それ自体の HTML マークアップを書き込むストリームを受信します。AJAX モデルにおける要求の応答は、サーバーで生成された HTML だけでなく、JavaScript Object Notation (JSON)、XML、シンジケーション、その他任意のものとしてシリアル化された生データである可能性があります。
BST パターンとは、要求によって生データがクライアントに返される状態を表します。一方、HTM パターンとは、要求によってすぐに表示できるマークアップが返される状態を表します。
拡張された BST の実装
先月号のソース コードでは、3 つの HTML テンプレートを入力として受け取り、それをデータ コレクションに対して反復処理し、その結果生成される HTML テキストを返す JavaScript クラスを作成しました。図 2 の JavaScript コードは、そのコードの最も重要な部分です。

図 2 テンプレートを取得する
function pageLoad()
{
if (builder === null)
{
builder = new Samples.MarkupBuilder();
builder.loadHeader($get("header"));
builder.loadFooter($get("footer"));
builder.loadItemTemplate($get("item"));
}
}
function getLiveQuotes()
{
Samples.WebServices.LiveQuoteService.Update(onDataAvailable);
}
function onDataAvailable(results)
{
var temp = builder.bind(results);
$get("grid").innerHTML = temp;
}
HTML テンプレートは、HTML 文字列として定義することも、ページに挿入された XML データ アイランドから読み込むこともできます。
<xml id="item">
<tr>
<td align="left">#Symbol</td>
<td align="right">#Quote</td>
<td align="right">#Change</td>
</tr>
</xml>
HTML テンプレートの任意の構文では、データバインド項目のプレースフォルダを見つけることができます。上記のサンプル コードの #Quote は、バインドされたデータ項目オブジェクトの Quote プロパティの値を表します。
このコードの質と実用性を高める方法はいくつかあります。改善すべき点として忘れてはならないのが、項目のスタイルを個別に設定する機能です。たとえば、クライアントにダウンロードされるデータが、大量の株式の現在の株価情報および価格変更であるとします。値上がりしている株式を緑色で、値下がりしている株式を赤色でレンダリングするとしましょう。そのためには、いくつかのロジックをレンダリング プロセスに挿入する必要があります。図 3 に、株式データのコレクションをいくつかの既存の HTML テンプレートにバインドするために使用する Samples.MarkupBuilder クラスの一部を示します (完全なコードは今月号のダウンロードに含まれています)。
MarkupBuilder クラスの心臓部は _generate メソッドです。このメソッドは、テンプレートをデータとマージする役割を担います。図 3 では、_generate メソッドはデータとコールバックの 2 つの引数を受け取ります。先月紹介したコードでは、このメソッドが受け取る引数はデータ引数だけでした。

図 3 MarkupBuilder クラス
function Samples$MarkupBuilder$_generate(data, itemCallback)
{
var pattern = /#\w+/g; // Finds all #word occurrences
var _builder = new Sys.StringBuilder(this._header);
for(i=0; i<data.length; i++)
{
var dataItem = data[i];
var template = this._itemTemplate;
var matches = template.match(pattern);
for (j=0; j<matches.length; j++)
{
var text = matches[j];
var memberName = text.slice(1);
//Invoke a callback to further modify data to be bound
var memberData = dataItem[memberName];
var temp = memberData;
if (itemCallback !== undefined)
{
temp = itemCallback(memberName, dataItem);
}
template = template.replace(matches[j], temp);
}
_builder.append(template);
}
_builder.append(this._footer);
// Return the markup
var markup = _builder.toString();
return markup;
}
クライアント開発の場合は、特定の項目に対してテンプレートを処理している間にビルダ クラスがコールバックする JavaScript 関数も指定します。コールバック関数は、次のプロトタイプを備えている必要があります。
function applyFormatting(memberName, dataItem)
1 つ目の引数は、最初にシャープ記号 (#) が付いていない、プレースフォルダの名前です。ほとんどの場合、1 つ目の引数はバインドされたオブジェクトのパブリック プロパティの名前と一致します。2 つ目の引数は、テンプレートの現在のインスタンスにバインドされているデータ項目オブジェクト全体です。
データ オブジェクト全体を使用できる場合、実行時の条件を十分にチェックしてマークアップのバリエーションを特定できます。この方法で設計した場合、コールバック関数は、ASP.NET サーバー コントロールのサーバー側 DataBound イベントと論理的に同等になります。次のコード スニペットは、株価の上昇または下落に基づいて株価の色を変更するのに必要な JavaScript コードです。
function applyFormatting(memberName, dataItem)
{
var temp = dataItem[memberName];
if (memberName == "Change" && x.charAt(0) == "+")
{
return "<span style='color:green;'>" + temp + "</span>";
}
if (memberName == "Change" && x.charAt(0) == "-")
{
return "<span style='color:red;'>" + temp + "</span>";
}
return temp;
}
コード内のロジックは、#Change プレースフォルダに対してコールバックが呼び出された場合にのみ適用されます。別のメンバに対してコールバックが呼び出された場合は、単に生のメンバ値を返します。ページへの最終的な効果については、図 4 を参照してください。
図 4 ブラウザのカスタマイズされたデータ バインド (クリックすると拡大画像が表示されます)
図 4 の一部のセルに対して、どのような方法で異なる背景色を割り当てているのかと疑問に思われるかもしれません。上記ではコールバックをデータバインド関数として説明しましたが、実際のコールバックの呼び出しは、#xxx という表現を含む項目テンプレートで見つかった一致項目に対して行われます。これは、#xxx プレースフォルダをテンプレート タグに挿入することで、コールバックの呼び出しを意図的に設定し、HTML コードを事実上どこにでも挿入できるということを意味します。その例を次に示します。
<xml id="item">
<tr>
<td align="left">#Symbol</td>
<td #Style1 align="right">#Quote</td>
<td align="right">#Change</td>
</tr>
</xml>
#Style1 という表現はプレースフォルダとして解釈されるため、コールバックが処理されます。コールバックの呼び出しには、疑似メンバの名前 (ここでは Style1) と現在のデータ項目が付随します。提供された情報に基づき、コールバックでホスト タグの背景色を淡い黄色に変更できます (そのセルが価格の上昇している株式をレンダリングするために使用されている場合)。
function applyFormatting(memberName, dataItem)
{
if (memberName == "Style1")
{
if (dataItem["Change"].charAt(0) == "+")
return "style='background-color:lightyellow;'";
else
return "";
}
...
}
ASP.NET では、ほとんどのテンプレートベースのコントロールはデータバインド規則をヘッダーおよびフッター領域には適用しません。Samples.MarkupBuilder コンポーネントも例外ではありません。とはいえ、表示されているデータから派生した情報をフッターに表示する必要がある場合もあります。フッター (またはヘッダー) テンプレートにスクリプト可能な要素を定義することで、これを簡単に実現できます。
<xml id="footer">
<tr>
<td colspan="3" align="right"
style="background- color:#eeeeee;">
<small><i>provided by <b id="lblProvider"></b></i></small>
</td>
</tr>
</table>
</xml>
TD タグのコンテンツには、一意の ID を持つ <b> タグが含まれています。その要素をさらにスクリプト可能にするには、これで十分です。XML データ アイランドのコンテンツはリモート WCF サービスから収集された生データとマージされ、準備が整いしだい、HTML ブラウザ要素の innerHTML プロパティを通じてページ オブジェクト モデルに挿入されることに注意してください。
これが行われると、ブラウザは HTML のコンテンツを自動的に解析し、ドキュメント オブジェクト モデル (DOM) を更新します。このようにして、一意の ID 文字列を含むリテラル要素はスクリプト可能になります。次の関数のサンプルは、株価情報を提供するリモート WCF サービスの呼び出しに関連付けられているコールバックです。
function onDataAvailable(results)
{
// Bind data and update the UI
var temp = builder.bind(results, applyFormatting);
$get("grid").innerHTML = temp;
$get("lblProvider").innerHTML = results[0].ProviderName;
}
ページ要素の innerHTML プロパティが更新され、特定の ID (ここでは lblProvider) を持つ要素が追加された後で、その要素のスクリプティングを開始できます。
BST パターンでは、ブラウザに必要な HTML は JavaScript を使用して生成する必要があります。図 1 に示すように、すべてのプレゼンテーション ロジックを 1 つの層に分離できるため、これは一般的に好ましい手法です。
さらに、テンプレートと JavaScript コールバックを使用することで、本質的に動的な HTML に対処することができ、データの特性に対応してユーザーの期待に応えることができるようになります。テンプレートは、コードの柔軟性と管理のしやすさを両立させるうえで非常に役に立ちます。ここで紹介した MarkupBuilder のような汎用クラスは、必要なものを揃え、範囲を狭める役割を果たします。JavaScript だけに頼って HTML を生成したり、分散したプレゼンテーション ロジックに生成を結び付けたりすることは適切ではありません。コードはすぐに複雑化し、読みにくくなります。エラーが多数発生する状態になるのも避けられません。このような状況から救い出してくれるのが、Microsoft® クライアント AJAX ライブラリを使用して作成されたヘルパー クラスです。
InnerHTML と DOM
HTML Message パターン (AJAX アプリケーションで HTML マークアップを生成するためのもう 1 つの方法) を呼び出す前に、innerHTML について説明しましょう。DOM は標準の API です。これを通じて、ブラウザは現在表示されているページのコンテンツをプログラムで公開します。DOM では、ページを要素のツリーとして表します。論理ツリーの各ノードは、既知の動作と固有の ID を持つ有効なオブジェクトに対応します。
DOM ノードでは、3 つの基本的な操作を実行できます。それは、ノードの検出、ノードの作成、およびノードの操作です。特定のノードの識別は、対応する要素の ID を把握している限りは簡単です。API には便利な関数が用意されています。
var node = document.getElementById(id);
ASP.NET AJAX では、getElementById 関数は $get 関数にラップされます。同じ ID を持つ複数の要素が存在する場合、関数はコレクション内で最初に現れる要素を返します。DOM サブツリーを更新するには、不要な要素を削除し、新しい要素を追加する必要があります。これは設計の観点からすると簡潔でわかりやすいアプローチですが、パフォーマンス的には問題があります。
ほぼすべてのブラウザにおいて、その DOM 要素の innerHTML プロパティがサポートされています。HTML は、特定の要素の開始タグと終了タグの間で設定または取得されます。このプロパティは Internet Explorer
® 4.0 の DHTML オブジェクト モデルで導入されましたが、正式な DOM API になることはありませんでした。しかし、innerHTML の処理は DOM API と比べてはるかに迅速です。特に、要素の複雑な構造体を作成する場合に顕著になります。innerHTML と DOM のパフォーマンスについては、
go.microsoft.com/fwlink/?LinkId=116828 で詳しく説明されています。innerHTML にも問題はあります。把握しておく必要のある問題については、
go.microsoft.com/fwlink/?LinkId=116827 を参照してください。
HTML Message パターン
HTM パターンの目的は、ブラウザで表示される HTML マークアップのブロックをサーバーで生成させることです。たとえば、リモート URL (サービスまたは HTTP ハンドラ) の呼び出しの実行と、すぐに表示できる HTML スニペットの受信から成る実装が可能です。
HTM の実装は、サーバー (具体的には AJAX サービス層) 上のコードに完全に依存します。これも、AJAX 固有の中間層の作成をお勧めする大きな理由の 1 つです。この中間層により、AJAX やプレゼンテーションのニーズおよび懸念事項からコア サービスを切り離すことができます (図 1 を参照)。
AJAX アプリケーションで HTML Message パターンをサポートするには、割り当てられたタスクを実行し、その計算結果を HTML スニペットに変換できるサービスが必要になります。図 5 にこのサービスを示します。
図 5 HTML Message をサポートするサービス (クリックすると拡大画像が表示されます)
ここからは、サービスのコンポーザビリティの原則がよくわかります。この原則は、再利用性の原則のバリエーションにすぎません。一般に、この原則はサービス指向アーキテクチャ (SOA) に適用されます。SOA では、Web Services Business Process Execution Language (WS-BPEL) のような構成言語を使用してビジネス プロセスを編成し、いくつかのプロセスを組み合わせることで親サービス プロセスを構成します。
HTML を出力する AJAX サービスは、データを取得するコア サービスと、データを HTML に変換するレンダラ サービスの組み合わせとして考えることができます。図 6 に、株価情報を返すサービスの構成アーキテクチャを示します。
図 6 HTML Message をサポートする株価情報サービス (クリックすると拡大画像が表示されます)
この実装では、親およびラッパー サービスを取得するためのクラスを構成しているにすぎません。設計の観点からすると、図 6 の複数のクラスはサービス (株価情報プロバイダ、データ ファインダ、出力レンダラ、およびこのコラムの後半で説明する入力アダプタ) として扱われます。
HTM パターンを実装する
図 7 に、HTM パターンの実装サンプルで使用している株価情報サービスのコントラクトを示します。このサービスは、オフラインおよびオンライン データ プロバイダを中心に構築されています。オフライン データ プロバイダは、株価と価格変更の古い値を返します。一方、オンライン プロバイダは、実際の財務サービスに接続してライブ データを返します。

図 7 サンプル StockQuote サービスのコントラクト
namespace Samples.Services.FinanceInfo
{
[ServiceContract(Namespace="Samples.Services",
Name="FinanceInfoService")]
public interface IFinanceInfoService
{
[OperationContract]
StockInfo[] GetQuotes(string symbols, bool isOffline);
[OperationContract(Name="GetQuotesOffline")]
StockInfo[] GetQuotes(string symbols);
[OperationContract(Name="GetQuotesFromConfig")]
StockInfo[] GetQuotes(bool isOffline);
[OperationContract(Name = "GetQuotesFromConfigOffline")]
StockInfo[] GetQuotes();
[OperationContract(Name = "GetQuotesOfflineAsHtml")]
string GetQuotesAsHtml(string symbols, bool isOffline);
[OperationContract(Name = "GetQuotesFromConfigAsHtml")]
string GetQuotesAsHtml(bool isOffline);
[OperationContract(Name = "GetQuotesFromConfigAsHtmlEx")]
string GetQuotesAsHtml(string contextKey);
}
}
どちらのプロバイダも、実際にデータを取得するために内部ファインダ コンポーネントを使用します。ファインダ コンポーネントには、インターフェイスと実際のファインダ クラスが構成ファイルから読み取られるという特徴があります。オフライン プロバイダの既定のファインダ コンポーネントは、Microsoft .NET Framework Random クラスを使用して乱数だけを生成します。オンライン プロバイダのファインダ コンポーネントは、財務情報を返す任意のパブリック Web サービスを使用できます。
ファインダ クラスによって取得されたデータは、レンダラ クラスを使用して HTML スニペットとして構成されます。レンダラ コンポーネントはインターフェイスを公開します。このコンポーネントは、構成ファイル内の設定を変更するだけで置き換えることができます。既定の HTML レンダラは、ハードコーディングされたスタイルでテーブルを構築します。今月のソース コードをご覧になると、実際の HTML レンダラは、最新の更新ラベルも追加する既定のレンダラから派生したクラスであることがおわかりになるでしょう。以下のコード スニペットは、ファインダ クラスおよびレンダラ クラスのインターフェイスを示しています。
namespace Samples.Services.FinanceInfo
{
public interface IFinanceInfoFinder
{
string ProviderName { get; }
StockInfo[] FindQuoteInfo (string symbols);
}
public interface IFinanceInfoRenderer
{
string GenerateHtml (StockInfo[] stocks);
}
}
ファインダで取得されたデータがレンダラのメソッドに直接渡されるので、インターフェイスにより円滑な相互運用性が実現されます。
この実装では、レンダラの GenerateHtml メソッドにより、事前に定義されているいくつかの設定に基づいてテーブルが構築されます。通常は、クライアントから渡されるその他のスタイル情報も使用できます。ただし、この株価情報サービスは、サーバーで正式な HTML ジェネレータとして構成されているレンダラ "サービス" を使用するように設計されています。この "サービス" に求められるのは、前の IFinanceInfoRenderer インターフェイスを実装することだけです。
次に示すサンプルでは、株価情報サービスを介して生成されたマークアップを使用しています。
function getLiveQuotes()
{
var isOffline = $get("chkOffline").checked;
Samples.Services.FinanceInfoService.GetQuotesFromConfigAsHtml
(isOffline,
onDataAvailable);
}
function onDataAvailable(results)
{
// Update the UI
$get("grid").innerHTML = results;
}
getLiveQuotes 関数は、ボタン クリックなどのクライアント側のイベントやタイマ コールバックにアタッチされます。図 8 は、サンプル ページを実行したところです。HTML マークアップは、JSON パッケージを使用してクライアントに戻されます。
図 8 HTML Message パターンを実行する (クリックすると拡大画像が表示されます)
パフォーマンスと設計に関する考慮事項
HTML Message パターンの場合、UI の生成はサーバー (特に、クライアントから呼び出すサーバー) で行われるようになります。このモデルには長所と短所があります。一方では、マネージ コードを使用してマークアップの生成に必要な複雑なロジックを実装できるという長所があります。サーバーでは、ブラウザでは確保できないプログラミング能力を活用して、構成ファイルを読み取り、リモート サービスに接続し、HTML テンプレートのデータベースにアクセスできます。
その一方で、デザイナなどのビジュアル ツールの力を借りずに、マークアップを生成するコードを記述しなければなりません。マークアップに必要な変更には、C# コードを使用して対処する必要があります。また、レイアウト、データ、分離コードを明確に分けることができません。
その回避策は、サーバー間シナリオでサービスがマークアップを照会する内部 ASP.NET ページの定義にあります。テンプレートとして機能するこれらのページは、Visual Studio® 2008 で作成できます。また、AJAX サービス層をホストする同じ IIS アプリケーションに展開できます。これらのページはプログラムで呼び出され、ページから返されるマークアップはクライアントに転送されます。
HTML Message パターンでは、生データを返すサービスのプレーンな呼び出しよりも多くのトラフィックが生成される傾向にあります。ただし、HTML Message パターンのトラフィックは、結果的には部分的なレンダリングによるトラフィックよりも少なくなることに注意してください。追加するスタイルおよび HTML 拡張が多いほど、返すパケットのサイズも大きくなります。
この点を踏まえて、HTML スタイル設定を HTML レイアウトとは切り離し、スタイル設定のためにクライアント側 CSS クラスへの参照だけをマークアップに埋め込むことができます。HTML マークアップをレイアウトとデータだけに限定すると、転送される余分なデータ (生データ以外のデータ) の割合を大幅に低減できます。実験中に私が気が付いたのは、表示する必要のあるフィールドが少ないときに、スタイル設定のために CSS クライアント クラスの参照だけを埋め込んだ場合、HTML Message パターンで構築されるページのトラフィックは、BST パターンで構築されるページのトラフィックよりもさらに少なくなることがあるということです。
DynamicPopulate エクステンダ
締めくくりとして、AJAX Control Toolkit に含まれているエクステンダの 1 つ、DynamicPopulate エクステンダについて説明します。このエクステンダは、HTML Message サービスで活用できます。
クライアント トリガ コントロール (ここではボタン) にバインドされたエクステンダは、サービス メソッドを呼び出し、結果を DOM 要素の innerHTML プロパティにアタッチします。言うまでもありませんが、DynamicPopulate エクステンダには AJAX サービス層の HTML Message サービスが必要です。
<act:DynamicPopulateExtender runat="server"
ID="DynamicPopulateExtender1"
BehaviorID="DynamicPopulateExtender1"
ClearContentsDuringUpdate="false"
TargetControlID="grid"
UpdatingCssClass="updating"
ServicePath="LiveQuotes.svc"
ServiceMethod="GetQuotesFromConfigAsHtmlEx"
/>
DynamicPopulate エクステンダによっても、図 6 の入力アダプタ サービスで強調表示されているサービスに新たな要件が課されます。ServiceMethod 属性経由で参照されるメソッドは、次のプロトタイプを備えている必要があります。
string MethodName(string contextKey);
contextKey パラメータには、サービス メソッドが処理方法を認識しているフォーマットでシリアル化された、あらゆるデータを含めることができます。入力アダプタ サービス クラスでは、入力文字列を受け取り、その文字列をサービスの他のクラスが処理方法を認識している、より具体的なパラメータに変換します。
エクステンダの使用時に直面する可能性のある問題の 1 つは、ユーザーがボタンをクリックした際の既定のイベントがエクステンダによって阻止されないということです。そのため、ボタンが ASP.NET ボタンの場合、引き続きポストバックが発生し、サービス呼び出しが無効化されます。次に、DynamicPopulate エクステンダのより一般的な使用方法を示します。
<asp:Button runat="server" id="btnRefresh" text="Live Quotes"
onclientclick="invoke();return false;" />
アタッチされた JavaScript の単純な関数は、次の処理を行います。
function invoke()
{
var extender = $find("DynamicPopulateExtender1");
var isOffline = $get("chkOffline").checked;
extender.populate(isOffline.toString());
}
このコードに基づき、HTML 応答をエクステンダの TargetControlID プロパティを通じて指定した要素と結合することで、UI が更新されます。
現時点でのソリューション
HTML はプレゼンテーションに使用されます。一方、XML、JSON、および RSS は、サーバーで生成されたデータをクライアントに移動するフォーマットです。データはクライアントでプレゼンテーション用に処理できます。AJAX のコンテキストにおいてこの整然としたモデルの妨げとなるのが、JavaScript 言語の使用です。データをクライアントにダウンロードした後で UI を構築するには、JavaScript を使用するしかありません。カスタム データ バインドおよびテンプレートの手法としての BST パターンは、必要な UI を作成するうえで役立ちます。
あなたがサーバー重視の考え方を持ち、JavaScript の使用を避けたいと思っている場合はどうすればよいでしょうか。UI が特に複雑で、より信頼性の高い強力な開発ツールとデバッグ ツールを使用することを望んでいる場合はどうでしょう。かなり大きなデータ構造に対する高負荷なアルゴリズムをサーバーとクライアントの両方で使用することになった場合は、どうすればよいでしょう。HTML 応答では、クライアントでの懸念を払拭できないのでしょうか。
一般的に言って、リッチなクライアント側オブジェクト モデルを備えた強力なコントロール セットが登場するまでは、HTML をプレゼンテーションに使用して JSON をデータに使用する、好ましいモデルを常に採用できるとは限りません。AJAX プレゼンテーションに関して言えば、現時点では、このモデルをあらゆる状況で利用するわけにはいきません。そのため、HTML Message パターンに目を向ける必要があるのです。このパターンはあらゆる目的に役立つわけではありませんが、特定の領域で力を発揮します。