XMLHTTP を使用した動的なページ更新

文書翻訳 文書翻訳
文書番号: 893659 - 対象製品
ASP.NET Support Voice コラム

XMLHTTP を使用した動的なページ更新

マイクロソフトは、ユーザーの要望に応じたコラムを作成したいと考えています。興味のあるトピック、「サポート技術情報」 (Microsoft Knowledge Base) や「Support Voice コラム」でこれから取り上げてほしいテーマについてのご意見をお待ちしています。Ask For It のフォームを使用して、ご意見やご感想をお寄せください。このコラムの末尾にも、このフォームへのリンクを掲載しています。
すべて展開する | すべて折りたたむ

目次

はじめに

Web アプリケーションの操作性について調査するとき、私はよく、妻が Web サイトをナビゲートするところを観察します。彼女は、技術的な事柄 (彼女の言葉を借りれば "退屈なこと") については簡単なことであってもほとんど知識を持っていませんが、彼女のインターネット ナビゲーションの腕前はなかなかのものです。

先日の夕方、妻が、ある大企業の電子商取引サイトを夢中になって調べているのを見ていました。彼女はたくさんのドロップダウンを使用して商品リストの階層をたどっていきましたが、彼女が選択するごとに、前に選択した内容が画面に表示されました。ドロップダウンで 1 つの項目をクリックすると、その都度、次のドロップダウンの情報を取得するためにページがポスト バックされるのです。これは、彼女にとってもどかしい処理でした。なぜなら、ポスト バックが起こるために、次のページに進むまでに長い時間がかかるように思えたからです。

私の妻が経験したレベルのストレスは、アプリケーション開発者がデータの取得に (ポスト バックではなく) XMLHTTP を使用するだけで簡単に軽減できます。今月のコラムでは、このことについて取り上げます。ポスト バックではなく XMLHTTP を使用して、Microsoft ASP.NET Web サービスから取得したデータで Web ページの一部を更新する方法について紹介します。とても魅力的なサイトを作成できます。私を信じて、コラムを読んでください。

概要

XMLHTTP は、クライアントから Web サーバーに要求が発行され、その要求に対して XML データ群を返すことで機能します。受け取る XML の構造に応じて XSLT や XML DOM を使用してデータを操作し、ページの一部をデータにバインドすることができます。これは、きわめて強力な手法です。

: マイクロソフトは、Internet Explorer に対応した Web サービス機能を提供しています。これにより、ASP.NET Web サービスに対する非同期呼び出しを迅速かつ簡単に実行できます。ただし、この機能はサポートされておらず、ページを非同期的に更新する最適な方法ではありません。これを行うには、代わりに XMLHTTP を使用する必要があります。

このコラムで取り上げるサンプルでは、XMLHTTP 経由で ASP.NET Web サービスを呼び出す 3 つの Web サービスを紹介します。Web サービスはローカルの SQL Server 上にある Northwind データベースに対してクエリを実行し、XML DiffGram の形式でクライアントにデータセットを返します。そして、XML DOM を使用して XML データを解析し、対象ページの該当部分を動的に更新します。ポスト バックを使用せずに、これらのすべての処理を行います。

Web サービス

ここでは、DynaProducts という名前の Web サービスを使用します。これは C# 言語で記述された基本的な ASP.NET Web サービスで、次の 3 つのメソッドを実装しています。
  • GetCategories : [商品区分] テーブルにあるすべての商品区分が含まれる 1 つのデータセットを返します。
  • GetProducts : メソッドに渡される商品区分に該当するすべての商品が含まれる 1 つのデータセットを返します。
  • GetProductDetails : メソッドに渡される ProductID に該当する商品の詳細情報が含まれる 1 つのデータセットを返します。

HTML ページ

ASP.NET Web サービス経由で更新するページが ASP.NET ページではないことを、最初にお伝えしておきます。これは通常の HTML ページですが、クライアント側にかなりの量の JavaScript を追加しています。このスクリプトを使用して、Web サービスの呼び出しを行います。

HTML ページのコード (抜粋) をご覧ください。
var objHttp;
var objXmlDoc;

function getDataFromWS(methodName, dataSetName, wsParamValue, wsParamName)
{

    // create the XML object
    objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");

    if (objXmlDoc == null)
    {
        alert("Unable to create DOM document!");
        
    } else {

	    // create an XmlHttp instance
	    objHttp = new ActiveXObject("Microsoft.XMLHTTP");
	
	
	    // Create the SOAP Envelope
	    strEnvelope = "<soap:Envelope xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
	
	            " xsd=\"http://www.w3.org/2001/XMLSchema\"" +
	
	            " soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
	
	            "  <soap:Body>" +
	
	            "    <" + methodName + " xmlns=\"http://jimcoaddins.com/DynaProducts\">" +
	
	            "    </" + methodName + ">" +
	
	            "  </soap:Body>" +
	
	            "</soap:Envelope>";
	
	
	    // Set up the post
	    objHttp.onreadystatechange = function(){
	
	        // a readyState of 4 means we're ready to use the data returned by XMLHTTP
	        if (objHttp.readyState == 4)
	        {
	
	            // get the return envelope
	            var szResponse = objHttp.responseText;
							
	            // load the return into an XML data island
	            objXmlDoc.loadXML(szResponse);
	
	            if (objXmlDoc.parseError.errorCode != 0) {
	                var xmlErr = objXmlDoc.parseError;
	                alert("You have error " + xmlErr.reason);
	            } else {
	
	                switch(dataSetName)
	                {
	                    case "CategoriesDS":
	                        processCategory();
	                        break;
	
	                    case "ProductsDS":
	                        processProducts();
	                        break;
	
	                    case "ProductDetailDS":
	                        processProductDetails();
	                        break;
	
	                }
	            }
	
	        }
	     }
	
	    var szUrl;
	    szUrl = "http://dadatop/wsXmlHttp/DynaProducts.asmx/" + methodName;
	
	    if (wsParamValue != null)
	    {
	
	        szUrl += "?" + wsParamName + "=" + wsParamValue;
	    }
	
	    // send the POST to the Web service
	    objHttp.open("POST", szUrl, true);
	    objHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	    objHttp.send(strEnvelope);
	  }
}
上記では、ページのコード ブロックをまとめて抜粋しました。どのような処理を行っているかを理解していただくために、以降で詳細を見ていきましょう。

スクリプトの先頭のブロックで、objHttp と objXmlDoc という 2 つの変数を作成しています。これらの変数は、XMLHTTP オブジェクトと XML DOM オブジェクトに使用します。次の行で getDataFromWS という関数を定義しています。この関数はクライアント側から Web サービスへの呼び出しを行うもので、次の 4 つの引数を受け取ります。4 つの引数のうち、2 つは省略可能です。
  • methodName : Web サービスを呼び出すためのメソッドの名前です。
  • dataSetName : Web サービスから返されるデータセットの名前です。
  • wsParamValue : 該当する場合に、Web サービスに渡されるパラメータの値です (省略可能です)。
  • wsParamName : 該当する場合に、Web サービスに渡されるパラメータの名前です (省略可能です)。
では、getDataFromWS 関数について細部を検討していきます。まず、最初の部分をご覧ください。
// create the XML object
    objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");

    if (objXmlDoc == null)
    {
    		alert("Unable to create DOM document!");

    } else {

		// create an XMLHTTP instance
		objHttp = new ActiveXObject("Microsoft.XMLHTTP");
このコード ブロックでは、XMLHTTP オブジェクトと XML Document オブジェクトを作成しています。次に、SOAP エンベロープを作成します。
// Create the SOAP Envelope
strEnvelope = "<soap:Envelope xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
	
          " xsd=\"http://www.w3.org/2001/XMLSchema\"" +
	
          " soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
	
          "  <soap:Body>" +
	
          "    <" + methodName + " xmlns=\"http://jimcoaddins.com/DynaProducts\">" +
	
          "    </" + methodName + ">" +
	
          "  </soap:Body>" +
	
          "</soap:Envelope>";
このコードでは、1 つの文字列変数に SOAP エンベロープを割り当てています。これは、Web サービスに渡すことができるようにするためです。Web サービスで使用できるように SOAP エンベロープの形式を指定する方法は、簡単にわかります。単に Web サービスを参照してメソッドの 1 つをクリックするだけです。クリックすると、そのメソッドに対応した SOAP エンベロープが表示されます。たとえば、この資料用に作成した wsXMLHTTP Web サービスの GetCategories メソッドを参照すると、次のように表示されます。

元に戻す画像を拡大する
envelope.png


このように、ASP.NET によって、HTTP POST や HTTP GET に対応する SOAP エンベロープ形式の指定方法が通知されます。この資料で紹介するサンプルでは、HTTP POST を使用します。

今までのところは、特に問題ないですね。では、コードの次のセクションに進みましょう。
// Set up the post
objHttp.onreadystatechange = function(){
	
// a readyState of 4	means we're ready to use the	data returned by	XMLHTTP
	if (objHttp.readyState == 4)
	{
	
		// get	the return envelope
		   var	szResponse	= objHttp.responseText;
	
		   // load	the return into an XML data island
		   objXmlDoc.loadXML(szResponse);
	
		   if (objXmlDoc.parseError.errorCode != 0) {
			var xmlErr =	objXmlDoc.parseError;
				 alert("You have error " + xmlErr.reason);
	}
	else	
	{

		switch(dataSetName)
				{
					case "CategoriesDS":
						processCategory();
						break;
					case "ProductsDS":
						processProducts();
						break;
					case "ProductDetailDS":
					processProductDetails();
						break;

				}
			}
XMLHTTP 経由で要求を発行すると、XMLHTTP オブジェクトは readyState プロパティを使用して要求のステータスを追跡します。Web サービスからすべてのデータが返されると、readyState プロパティの値は 4 に設定されます。XMLHTTP オブジェクトの onreadystatechange プロパティを使用すると、readyState プロパティの変更時に呼び出されるコールバック関数を設定できます。確実にデータ全体が受信されるようにすることで、準備が整うまでデータ処理を行わないようにできます。

すべてのデータを受信した時点で、responseText プロパティを使用して XML データ群を作成します。周知のとおり、Web サービスからの応答は XML 形式で返されます。このサンプルでは、Microsoft ADO.NET のデータセットを返しています。

コード ブロックの次のセクションでは、switch ステートメントを使用して、Web サービスから返されたデータセットの名前に応じて関数を呼び出します。この関数のコードについては、後で詳しく説明します。

ここでは、XMLHTTP 要求を実際に実行するコードを見てみましょう。
var szUrl;
	szUrl = "http://dadatop/wsXmlHttp/DynaProducts.asmx/" + methodName;
	
	if (wsParamValue != null)
	{
	
	      	szUrl += "?" + wsParamName + "=" + wsParamValue;
	}
	
// send the POST to the Web service
	objHttp.open("POST", szUrl, true);
	objHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	objHttp.send(strEnvelope);
変数 szUrl には、Web サービス呼び出しに使用する URL が明示的に含まれています。その次のステートメントは、QueryString 値として渡されるパラメータに対し、条件に応じて値を設定する if ステートメントです。使用環境によっては、SOAP エンベロープにパラメータを追加できます。いずれの方法でも、正常に動作します。

次に、XMLHTTP オブジェクトの open メソッドを呼び出します。open メソッドには、最初の 3 つのパラメータ (メソッド、URL、ブール値) を指定して、この呼び出しが非同期的であるかどうかを示します。
重要 : ここで紹介する方法と同じように非同期呼び出しを行う場合は、onreadystatechange プロパティを使用してコールバック関数を設定する必要があります。

content-type 要求ヘッダーを設定した後で、上記の手順で設定した文字列変数を使用して、要求を SOAP エンベロープとして送信します。

ここまでの説明で、XMLHTTP 要求を作成するコード全体を見てきました。では次に、ブラウザ上のインターフェイスと Web サービス呼び出しからの応答を処理するコードについて確認してみましょう。

まず、ページを最初に読み込むときに呼び出される関数をご覧ください。
function getCategories()
{

  var func = "getDataFromWS('GetCategories', 'CategoriesDS')";
  document.all.lblCategoryDropdown.innerText = 
"Please wait while data is retrieved...";
  window.setTimeout(func, 1);

  }
この関数では、まず、getDataFromWS 関数のシグネチャを格納する変数を作成します。この変数は、関数処理の最後で window.setTimeout を呼び出し、getDataFromWS 関数を呼び出すときに使用します。これは、ユーザーが Web サービスの呼び出しが完了するのを待機している間、そのステータスをユーザーに表示するための処理です。DIV の innerText を変更し、データの取得中であることを知らせるメッセージを表示していることに注意してください。次に、window.setTimeout 呼び出しを通して getDataFromWS 関数をスケジュールし、1 ミリ秒で実行するように設定します。

Web サービス応答の処理

この資料の前半に記載したコードでは、onreadystatechange プロパティを使用してコールバック関数を設定しました。また、そのコールバック関数には、データセット名に基づいて特定の関数を呼び出す switch ステートメントが含まれていたことにも留意します。このサンプルのデータセット名は CategoriesDS であるため、コールバック関数からは processCategory 関数が呼び出されます。では、processCategory 関数について、XML DOM を使用して Web サービスからの応答内容を解析する方法について見ていきましょう。
function processCategory()
{

  // get an XML data island with the category data
  objNodeList = objXmlDoc.getElementsByTagName("Categories");
 
  // add default value to the drop-down
  document.forms[0].drpCategory.options[0] = new Option("Select a Category", 0);

  // walk through the nodeList and populate the drop-down
  for (var i = 0; i < objNodeList.length; i++) 
  {
      var dataNodeList;
      var textNode;
      var valueNode;

      dataNodeList = objNodeList[i].childNodes;
      valueNode = dataNodeList.item(0);
      textNode = dataNodeList.item(1);

      document.forms[0].drpCategory.options[i + 1] = 
new Option(textNode.text, valueNode.text);
      document.all.lblCategoryDropdown.innerText = "Select a Category:";
      document.forms[0].drpCategory.style.visibility = "visible";
       
    }

  }
前述のコードで、getDataFromWS 関数の応答として得た XML を、objXmlDoc オブジェクトに読み込みました。processCategory 関数ではこの XML を使用して、その内容を解析し、[Select a Category] ドロップダウンに設定します。

最初に、XML 応答内容の一部を使用して IXMLDOMNodeList オブジェクトを作成します。Web サービス呼び出しからは、DiffGram の形式でデータセットが返されます。応答の中で必要なのは、データセットに挿入した DataTable の内容です。DataTable を含む XML ブロックで IXMLDOMNodeList オブジェクトを作成することで、それを取得できます。

Web サービスのコードを参照すると、Categories という名前の DataTable が作成され、それがデータセットに追加されたことがわかります。Web サービスから返された XML では、データセットは <CategoriesDS> ブロック内に含まれ、DataTable の各行は別の <Categories> ブロックに含まれています。以下の XML ファイルを参照してください。

下記のファイルは、「Microsoft ダウンロード センター」からダウンロードできます。
元に戻す画像を拡大する
ダウンロード
GetCategories.xml パッケージ
元に戻す画像を拡大する
ダウンロード
WSXMLHTTP.exe パッケージ マイクロソフトのサポート ファイルのダウンロード方法を参照するには、以下の「サポート技術情報」 (Microsoft Knowledge Base) をクリックしてください。
119591 オンライン サービスからマイクロソフトのサポート ファイルを入手する方法
マイクロソフトでは、アップロード時点の最新のウイルス検査プログラムを使用して、配布ファイルのウイルス チェックを行っています。配布ファイルはセキュリティで保護されたサーバー上に置かれており、権限のない第三者が無断でファイルを変更できないようになっています。

DataTable を含む XML ブロックを取得するため、次のコードを使用します。
objNodeList = objXmlDoc.getElementsByTagName("Categories");
このコードにより、各 <Categories> ノードを含む IXMLDOMNodeList オブジェクトが返されます。for ループを使用して、ノード リスト内で処理を繰り返します。
// walk through the nodeList and populate the drop-down
  for (var i = 0; i < objNodeList.length; i++) 
  {
      var dataNodeList;
      var textNode;
      var valueNode;

      dataNodeList = objNodeList[i].childNodes;
      valueNode = dataNodeList.item(0);
      textNode = dataNodeList.item(1);

      document.forms[0].drpCategory.options[i + 1] = 
new Option(textNode.text, valueNode.text);
      document.all.lblCategoryDropdown.innerText = "Select a Category:";
      document.forms[0].drpCategory.style.visibility = "visible";
       
    }
<Categories> の各ノードには、必要な 2 つのノード (<ID> ノードと <CategoryName> ノード) が含まれていることがわかっています。このため、まず新たな IXMLDOMNodeList を作成し、現在の <Categories> ノードの子ノードと共に設定します。
dataNodeList = objNodeList[i].childNodes;
次に、item メソッドを使用して、ドロップダウンを設定するために必要な両方のノードにアクセスします。最初のノードにはデータベースの CategoryID フィールドが含まれ、2 番目のノードにはデータベースの CategoryName フィールドが含まれています。Option オブジェクトを新規作成し、CategoryName にテキスト、CategoryID に値をそれぞれ設定して、drpCategory ドロップダウンに追加します。関数の残りのコードでは、XML 応答から必要なデータを取り出してページの該当部分に設定するときと同じメソッドを使用します。

: このサンプルで処理しているのは少量のデータであるため、必要なデータの取り出しに使用する方法は DOM で十分です。大量のデータを扱う場合は、XSLT を選択することもできます。

正常に動作させる方法

上記では、このコードのしくみについて説明しました。以下では、サンプル ファイルを期待どおりに動作させる方法について、詳しく説明します。

Web サービスの展開

ASP.NET Web サービスを展開する方法は、単に、添付の Web サービス サンプル ファイルを Web サーバーのルートに解凍するだけです。解凍したら DynaProducts.asmx のコードを開き、接続文字列を変更します。少なくとも SA パスワードの入力は必要です。変更を加えたら、Web サービスを再コンパイルします。

HTML ファイルの展開

HTML ファイルには、szUrl という名前の変数が含まれています。この変数には、Web サービス呼び出しに使用する URL が含まれています。この変数は、getDataFromWS 関数の最後の方に記述されています。この URL を、上記で展開した Web サービスの URL に変更する必要があります。

Web サービスと HTML ファイルの両方を展開したら、HTML ファイルをブラウザで開きます。ページが読み込まれると、Web サービスに対する最初の XMLHTTP 要求によって [Select a Category] ドロップダウンが設定されます。ドロップダウンが設定されたら、商品区分を選択し、[Products] ドロップダウンを設定するための次の XMLHTTP 要求を起動します。[Products] ドロップダウンから商品を選択すると、選択した商品に関する情報がテーブルに設定されます。

これらの XMLHTTP 要求を処理する間、ページではポスト バックが行われていないことに注目します。これが、XMLHTTP 要求処理の魅力的な点です。処理するデータ量の多いページであっても、ユーザーに対してページが "ちらつく" ことなく、スクロール ポジションが維持されます。これは強力な機能です。

もう 1 つ、付け加えます。この資料では、XMLHTTP を使用して Web サービスにクエリを実行しました。ASPX ページや ASP ページに要求を発行するときにも簡単に使用できると考えたからです。この手法には、無限の可能性があります。今後の Web アプリケーション開発で、XMLHTTP が役に立つことを願っています。
興味のあるトピック、「サポート技術情報」 (Microsoft Knowledge Base) でこれから取り上げて欲しいテーマについてのご意見をお待ちしています。Ask For It のフォームを使用して、ご意見やご感想をお寄せください。

プロパティ

文書番号: 893659 - 最終更新日: 2005年12月20日 - リビジョン: 5.2
この資料は以下の製品について記述したものです。
  • Microsoft ASP.NET 1.0
  • Microsoft ASP.NET 1.1
キーワード:?
kbgraphic kbscript kbxml kbhowto KB893659
"Microsoft Knowledge Baseに含まれている情報は、いかなる保証もない現状ベースで提供されるものです。Microsoft Corporation及びその関連会社は、市場性および特定の目的への適合性を含めて、明示的にも黙示的にも、一切の保証をいたしません。さらに、Microsoft Corporation及びその関連会社は、本文書に含まれている情報の使用及び使用結果につき、正確性、真実性等、いかなる表明・保証も行ないません。Microsoft Corporation、その関連会社及びこれらの権限ある代理人による口頭または書面による一切の情報提供またはアドバイスは、保証を意味するものではなく、かつ上記免責条項の範囲を狭めるものではありません。Microsoft Corporation、その関連会社 及びこれらの者の供給者は、直接的、間接的、偶発的、結果的損害、逸失利益、懲罰的損害、または特別損害を含む全ての損害に対して、状況のいかんを問わず一切責任を負いません。(Microsoft Corporation、その関連会社 またはこれらの者の供給者がかかる損害の発生可能性を了知している場合を含みます。) 結果的損害または偶発的損害に対する責任の免除または制限を認めていない地域においては、上記制限が適用されない場合があります。なお、本文書においては、文書の体裁上の都合により製品名の表記において商標登録表示、その他の商標表示を省略している場合がありますので、予めご了解ください。"

フィードバック

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com