ASP.NET AJAX Web サービスについて理解する

作成者: Scott Cate

Web サービスは、分散システム間でデータを交換するためのクロスプラットフォーム ソリューションを提供する .NET フレームワークの不可欠な部分です。 Web サービスは通常、異なるオペレーティング システム、オブジェクト モデル、およびプログラミング言語でデータの送受信を許可するために使用されますが、ASP.NET AJAX ページにデータを動的に挿入したり、ページからバックエンド システムにデータを送信したりするためにも使用できます。 これはすべてポストバック操作に頼ることなく行うことができます。

ASP.NET AJAX を使用した Web サービスの呼び出し

Dan Wahlin

Web サービスは、分散システム間でデータを交換するためのクロスプラットフォーム ソリューションを提供する .NET フレームワークの不可欠な部分です。 Web サービスは通常、異なるオペレーティング システム、オブジェクト モデル、およびプログラミング言語でデータの送受信を許可するために使用されますが、ASP.NET AJAX ページにデータを動的に挿入したり、ページからバックエンド システムにデータを送信したりするためにも使用できます。 これはすべてポストバック操作に頼ることなく行うことができます。

ASP.NET AJAX UpdatePanel コントロールは、ASP.NET ページを AJAX で有効にする簡単な方法を提供しますが、UpdatePanel を使用せずにサーバー上のデータに動的にアクセスする必要がある場合があります。 この記事では、ASP.NET AJAX ページ内で Web サービスを作成して使用することでこれを実現する方法について説明します。

この記事では、コア ASP.NET AJAX 拡張機能で使用できる機能と、AutoCompleteExtender と呼ばれる ASP.NET AJAX Toolkit の Web サービス対応コントロールに焦点を当てます。 対象となるトピックには、AJAX 対応 Web サービスの定義、クライアント プロキシの作成、JavaScript を使用した Web サービスの呼び出しなどがあります。 また、ページ メソッドに対して Web サービス呼び出しを直接行う方法 ASP.NET 確認します。

Web サービスの構成

Visual Studio 2008 を使用して新しい Web サイト プロジェクトを作成すると、web.config ファイルには、以前のバージョンの Visual Studio のユーザーにはなじみのない新しい追加が多数追加されています。 これらの変更の中には、"asp" プレフィックスを ASP.NET AJAX コントロールにマップして、ページで使用できるようにするものもあれば、必要な HttpHandlers と HttpModules を定義するものもあります。 リスト 1 は、Web サービス呼び出しに影響を <httpHandlers> 与えるweb.config内の 要素に加えられた変更を示しています。 .asmx 呼び出しの処理に使用される既定の HttpHandler は削除され、System.Web.Extensions.dll アセンブリにある ScriptHandlerFactory クラスに置き換えられます。 System.Web.Extensions.dllには、ASP.NET AJAX で使用されるすべてのコア機能が含まれています。

リスト 1。 ASP.NET AJAX Web サービス ハンドラーの構成

<httpHandlers>
     <remove verb="*" path="*.asmx"/>
     <add verb="*" path="*.asmx" validate="false"
          type="System.Web.Script.Services.ScriptHandlerFactory,
          System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,
          PublicKeyToken=31bf3856ad364e35"/>
</httpHandlers>

この HttpHandler の置き換えは、JavaScript Web サービス プロキシを使用して、ASP.NET AJAX ページから .NET Web Services への JavaScript Object Notation (JSON) 呼び出しを行えるようにするために行われます。 ASP.NET AJAX は、通常 Web サービスに関連付けられている標準の Simple Object Access Protocol (SOAP) 呼び出しとは対照的に、Web サービスに JSON メッセージを送信します。 これにより、要求メッセージと応答メッセージが全体的に小さくなります。 また、ASP.NET AJAX JavaScript ライブラリは JSON オブジェクトを操作するように最適化されているため、より効率的なクライアント側でのデータ処理が可能になります。 リスト 2 とリスト 3 は、JSON 形式にシリアル化された Web サービス要求メッセージと応答メッセージの例を示しています。 リスト 2 に表示される要求メッセージは、値が "Belgium" の country パラメーターを渡しますが、リスト 3 の応答メッセージは Customer オブジェクトの配列とそれに関連付けられているプロパティを渡します。

一覧 2. JSON にシリアル化された Web サービス要求メッセージ

{"country":"Belgium"}

> [!注] 操作名は、Web サービスへの URL の一部として定義されます。さらに、要求メッセージは常に JSON 経由で送信されるとは限りません。 Web サービスでは、UseHttpGet パラメーターを true に設定して ScriptMethod 属性を使用できます。これにより、クエリ文字列パラメーターを介してパラメーターが渡されます。

一覧 3. JSON にシリアル化された Web サービス応答メッセージ

[{"__type":"Model.Customer","Country":"Belgium","CompanyName":"Maison
     Dewey","CustomerID":"MAISD","ContactName":"Catherine
     Dewey"},{"__type":"Model.Customer","Country":"Belgium","CompanyName":"Suprêmes
     délices","CustomerID":"SUPRD","ContactName":"Pascale
     Cartrain"}]

次のセクションでは、JSON 要求メッセージを処理し、単純型と複合型の両方で応答できる Web サービスを作成する方法について説明します。

AJAX-Enabled Web サービスの作成

ASP.NET AJAX フレームワークには、Web サービスを呼び出すさまざまな方法が用意されています。 AutoCompleteExtender コントロール (ASP.NET AJAX Toolkit で使用可能) または JavaScript を使用できます。 ただし、サービスを呼び出す前に、クライアント スクリプト コードで呼び出すことができるように、AJAX を有効にする必要があります。

Web サービスの ASP.NET を初めて使用する場合でも、AJAX 対応サービスを簡単に作成できます。 .NET Framework では、2002 年の最初のリリース以降、ASP.NET Web サービスの作成がサポートされており、ASP.NET AJAX Extensions では、.NET フレームワークの既定の機能セットに基づいて構築された追加の AJAX 機能が提供されています。 Visual Studio .NET 2008 Beta 2 には、.asmx Web Service ファイルを作成するためのサポートが組み込まれており、System.Web.Services.WebService クラスからクラスの横に関連付けられているコードが自動的に派生します。 クラスにメソッドを追加するときは、Web サービス コンシューマーによって呼び出されるように WebMethod 属性を適用する必要があります。

リスト 4 は、GetCustomersByCountry() という名前のメソッドに WebMethod 属性を適用する例を示しています。

一覧 4. Web サービスでの WebMethod 属性の使用

[WebMethod]
public Customer[] GetCustomersByCountry(string country)
{
     return Biz.BAL.GetCustomersByCountry(country);
}

GetCustomersByCountry() メソッドは country パラメーターを受け取り、Customer オブジェクト配列を返します。 メソッドに渡された国の値はビジネス レイヤー クラスに転送されます。このクラスでは、データ レイヤー クラスを呼び出してデータベースからデータを取得し、Customer オブジェクトのプロパティにデータを入力し、配列を返します。

ScriptService 属性の使用

WebMethod 属性を追加すると、標準の SOAP メッセージを Web サービスに送信するクライアントから GetCustomersByCountry() メソッドを呼び出すことができますが、ASP.NET AJAX アプリケーションからすぐに JSON 呼び出しを行うことはできません。 JSON 呼び出しを許可するには、ASP.NET AJAX 拡張機能の ScriptService 属性を Web サービス クラスに適用する必要があります。 これにより、Web サービスは JSON を使用して書式設定された応答メッセージを送信でき、クライアント側スクリプトは JSON メッセージを送信してサービスを呼び出すことができます。

リスト 5 は、CustomersService という名前の Web サービス クラスに ScriptService 属性を適用する例を示しています。

一覧 5. ScriptService 属性を使用した Web サービスの AJAX 有効化

[System.Web.Script.Services.ScriptService]
[WebService(Namespace = "http://xmlforasp.net")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class CustomersService : System.Web.Services.WebService
{
     [WebMethod]
     public Customer[] GetCustomersByCountry(string country)
     {
          return Biz.BAL.GetCustomersByCountry(country);
     }
}

ScriptService 属性は、AJAX スクリプト コードから呼び出すことができることを示すマーカーとして機能します。 実際には、バックグラウンドで発生する JSON シリアル化または逆シリアル化タスクは処理されません。 ScriptHandlerFactory (web.configで構成) およびその他の関連クラスは、JSON 処理の大部分を行います。

ScriptMethod 属性の使用

ScriptService 属性は、ASP.NET AJAX ページで使用するために.NET Web サービスで定義する必要がある唯一の ASP.NET AJAX 属性です。 ただし、ScriptMethod という名前の別の属性を、サービスの Web メソッドに直接適用することもできます。 ScriptMethod では、 を含む UseHttpGetResponseFormat 3 つのプロパティを定義しますXmlSerializeString。 これらのプロパティの値を変更すると、Web メソッドで受け入れられる要求の種類を GET に変更する必要がある場合、Web メソッドが または XmlElement オブジェクトのXmlDocument形式で生 XML データを返す必要がある場合、またはサービスから返されたデータを常に JSON ではなく XML としてシリアル化する必要がある場合に便利です。

UseHttpGet プロパティは、WEB メソッドが POST 要求ではなく GET 要求を受け入れる必要がある場合に使用できます。 要求は、Web メソッドの入力パラメーターが QueryString パラメーターに変換された URL を使用して送信されます。 UseHttpGet プロパティの既定値は false で、操作が安全であることが判明した場合と、機密データが Web サービスに渡されない場合にのみ に設定 true する必要があります。 リスト 6 は、UseHttpGet プロパティで ScriptMethod 属性を使用する例を示しています。

一覧 6. UseHttpGet プロパティで ScriptMethod 属性を使用する。

[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string HttpGetEcho(string input)
{
     return input;
}

リスト 6 に示されている HttpGetEcho Web メソッドが呼び出されたときに送信されるヘッダーの例を次に示します。

GET /CustomerViewer/DemoService.asmx/HttpGetEcho?input=%22Input Value%22 HTTP/1.1

Web メソッドが HTTP GET 要求を受け入れることを許可するだけでなく、JSON ではなくサービスから XML 応答を返す必要がある場合に ScriptMethod 属性を使用することもできます。 たとえば、Web サービスはリモート サイトから RSS フィードを取得し、XmlDocument オブジェクトまたは XmlElement オブジェクトとして返します。 その後、XML データの処理がクライアントで行われる可能性があります。

リスト 7 は、ResponseFormat プロパティを使用して、Web メソッドから XML データを返す必要があることを指定する例を示しています。

一覧 7. ResponseFormat プロパティで ScriptMethod 属性を使用する。

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public XmlElement GetRssFeed(string url)
{
     XmlDocument doc = new XmlDocument();
     doc.Load(url);
     return doc.DocumentElement;
}

ResponseFormat プロパティは、XmlSerializeString プロパティと共に使用することもできます。 XmlSerializeString プロパティの既定値は false です。つまり、Web メソッドから返される文字列を除くすべての戻り値の型は、 プロパティが にResponseFormat.Xml設定されている場合ResponseFormatに XML としてシリアル化されます。 が にtrue設定されている場合XmlSerializeString、Web メソッドから返されるすべての型は、文字列型を含む XML としてシリアル化されます。 ResponseFormat プロパティの値が XmlSerializeString プロパティの ResponseFormat.Json 場合は無視されます。

リスト 8 は、XmlSerializeString プロパティを使用して文字列を強制的に XML としてシリアル化する例を示しています。

リスト 8. XmlSerializeString プロパティで ScriptMethod 属性を使用する

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml,XmlSerializeString=true)]
public string GetXmlString(string input)
{
     return input;
}

リスト 8 に示されている GetXmlString Web メソッドの呼び出しから返される値を次に示します。

<?xml version="1.0"?>
     <string>Test</string>

既定の JSON 形式では、要求メッセージと応答メッセージの全体的なサイズが最小限に抑えられますが、ブラウザー間の方法で AJAX クライアント ASP.NET 簡単に使用できますが、Internet エクスプローラー 5 以降などのクライアント アプリケーションで Web メソッドから XML データが返されることを想定している場合は、ResponseFormat プロパティと XmlSerializeString プロパティを使用できます。

複合型の操作

リスト 5 では、Web サービスから Customer という名前の複合型を返す例を示しました。 Customer クラスは、FirstName や LastName などのプロパティとして、いくつかの異なる単純型を内部的に定義します。 AJAX 対応 Web メソッドで入力パラメーターまたは戻り値の型として使用される複合型は、クライアント側に送信される前に JSON に自動的にシリアル化されます。 ただし、入れ子になった複合型 (別の型内で内部的に定義されたもの) は、既定ではスタンドアロン オブジェクトとしてクライアントで使用できません。

Web サービスで使用される入れ子になった複合型をクライアント ページでも使用する必要がある場合は、ASP.NET AJAX GenerateScriptType 属性を Web サービスに追加できます。 たとえば、リスト 9 に示されている CustomerDetails クラスには、入れ子になった複合型を表す Address プロパティと Gender プロパティが含まれています。

一覧 9. ここに示す CustomerDetails クラスには、入れ子になった 2 つの複合型が含まれています。

public class CustomerDetails : Customer
{
     public CustomerDetails()
     {
     }
     Address _Address;
     Gender _Gender = Gender.Unknown;
     public Address Address
     {
          get { return _Address; }
          set { _Address = value; }
     }
     public Gender Gender
     {
          get { return _Gender; }
          set { _Gender = value; }
     }
}

リスト 9 に示されている CustomerDetails クラス内で定義されている Address オブジェクトと Gender オブジェクトは、入れ子になった型であるため、JavaScript を介してクライアント側で自動的に使用することはできません (Address はクラス、Gender は列挙体)。 Web サービス内で使用される入れ子になった型をクライアント側で使用できる必要がある場合は、前述の GenerateScriptType 属性を使用できます (リスト 10 を参照)。 この属性は、入れ子になった異なる複合型がサービスから返される場合に複数回追加できます。 Web サービス クラスまたは特定の Web メソッドの上に直接適用できます。

リスト 10。 GenerateScriptService 属性を使用して、クライアントで使用できる入れ子になった型を定義します。

[System.Web.Script.Services.ScriptService]
[System.Web.Script.Services.GenerateScriptType(typeof(Address))]
[System.Web.Script.Services.GenerateScriptType(typeof(Gender))]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class NestedComplexTypeService : System.Web.Services.WebService
{
     //Web Methods
}

属性を GenerateScriptType Web サービスに適用すると、Address 型と Gender 型がクライアント側の ASP.NET AJAX JavaScript コードで自動的に使用できるようになります。 Web サービスに GenerateScriptType 属性を追加して自動的に生成され、クライアントに送信される JavaScript の例を、リスト 11 に示します。 入れ子になった複合型の使用方法については、後で説明します。

一覧 11. ASP.NET AJAX ページで使用できる入れ子になった複合型。

if (typeof(Model.Address) === 'undefined')
{
     Model.Address=gtc("Model.Address");
     Model.Address.registerClass('Model.Address');
}
Model.Gender = function() { throw Error.invalidOperation(); }
Model.Gender.prototype = {Unknown: 0,Male: 1,Female: 2}
Model.Gender.registerEnum('Model.Gender', true);

Web サービスを作成し、ASP.NET AJAX ページからアクセスできるようにする方法を見てきたので、データを取得したり Web サービスに送信したりできるように、JavaScript プロキシを作成して使用する方法を見てみましょう。

JavaScript プロキシの作成

標準の Web サービス (.NET または別のプラットフォーム) を呼び出す場合、通常は、SOAP 要求メッセージと応答メッセージの送信の複雑さから保護するプロキシ オブジェクトを作成する必要があります。 ASP.NET AJAX Web Service 呼び出しを使用すると、JavaScript プロキシを作成して使用して、JSON メッセージのシリアル化と逆シリアル化を気にすることなく、サービスを簡単に呼び出すことができます。 JavaScript プロキシは、ASP.NET AJAX ScriptManager コントロールを使用して自動的に生成できます。

Web サービスを呼び出すことができる JavaScript プロキシを作成するには、ScriptManager の Services プロパティを使用します。 このプロパティを使用すると、ポストバック操作を必要とせずに、ASP.NET AJAX ページで非同期的にデータの送受信を呼び出すことができる 1 つ以上のサービスを定義できます。 サービスを定義するには、ASP.NET AJAX ServiceReference コントロールを使用し、Web サービス URL をコントロールの Path プロパティに割り当てます。 一覧 12 は、CustomersService.asmx という名前のサービスを参照する例を示しています。

<asp:ScriptManager ID="ScriptManager1" runat="server">
     <Services>
          <asp:ServiceReference Path="~/CustomersService.asmx" />
     </Services>
</asp:ScriptManager>

一覧 12. ASP.NET AJAX ページで使用される Web サービスの定義。

ScriptManager コントロールを使用して CustomersService.asmx への参照を追加すると、JavaScript プロキシが動的に生成され、ページによって参照されます。 プロキシはスクリプト> タグを<使用して埋め込まれ、CustomersService.asmx ファイルを呼び出し、その末尾に /js を追加することによって動的に読み込まれます。 次の例は、web.configでデバッグが無効になっている場合に、JavaScript プロキシがどのようにページに埋め込まれるかを示しています。

<script src="CustomersService.asmx/js" type="text/javascript"></script>

>[!注] 生成された実際の JavaScript プロキシ コードを表示する場合は、目的の .NET Web サービスの URL をインターネット エクスプローラーのアドレス ボックスに入力し、末尾に /js を追加できます。

web.configでデバッグが有効になっている場合、次に示すように JavaScript プロキシのデバッグ バージョンがページに埋め込まれます。

<script src="CustomersService.asmx/jsdebug" type="text/javascript"></script>

ScriptManager によって作成された JavaScript プロキシは、スクリプト> タグの src 属性を使用して<参照されるのではなく、ページに直接埋め込むこともできます。 これを行うには、ServiceReference コントロールの InlineScript プロパティを true (既定値は false) に設定します。 これは、プロキシが複数のページ間で共有されていない場合や、サーバーに対するネットワーク呼び出しの数を減らしたい場合に便利です。 InlineScript が true に設定されている場合、プロキシ スクリプトはブラウザーによってキャッシュされないため、ASP.NET AJAX アプリケーション内の複数のページでプロキシを使用する場合は、既定値 false を使用することをお勧めします。 InlineScript プロパティの使用例を次に示します。

<asp:ServiceReference InlineScript="true" Path="~/CustomersService.asmx"/>

JavaScript プロキシの使用

ScriptManager コントロールを使用して ASP.NET AJAX ページから Web サービスを参照すると、Web サービスに対して呼び出しを行い、返されたデータをコールバック関数を使用して処理できます。 Web サービスは、その名前空間 (存在する場合)、クラス名、および Web メソッド名を参照することによって呼び出されます。 Web サービスに渡されるパラメーターは、返されたデータを処理するコールバック関数と共に定義できます。

JavaScript プロキシを使用して GetCustomersByCountry() という名前の Web メソッドを呼び出す例を、リスト 13 に示します。 GetCustomersByCountry() 関数は、エンド ユーザーがページ上のボタンをクリックしたときに呼び出されます。

一覧 13. JavaScript プロキシを使用した Web サービスの呼び出し。

function GetCustomerByCountry()
{
     var country = $get("txtCountry").value;
     InterfaceTraining.CustomersService.GetCustomersByCountry(country, OnWSRequestComplete);
}
function OnWSRequestComplete(results)
{
     if (results != null)
     {
          CreateCustomersTable(results);
          GetMap(results);
     }
}

この呼び出しは、サービスで定義されている InterfaceTraining 名前空間、CustomersService クラス、および GetCustomersByCountry Web メソッドを参照します。 テキスト ボックスから取得した国の値と、非同期 Web サービス呼び出しが返されたときに呼び出される OnWSRequestComplete という名前のコールバック関数を渡します。 OnWSRequestComplete は、サービスから返された Customer オブジェクトの配列を処理し、ページに表示されるテーブルに変換します。 呼び出しから生成された出力を図 1 に示します。

Web サービスに対して非同期の AJAX 呼び出しを行って取得したデータをバインドします。

図 1: Web サービスに対して非同期 AJAX 呼び出しを行って取得したデータをバインドする。 (クリックするとフルサイズの画像が表示されます)

JavaScript プロキシは、Web メソッドを呼び出す必要があるが、プロキシが応答を待機しない場合に、Web サービスを一方向に呼び出すこともできます。 たとえば、Web サービスを呼び出して、ワークフローなどのプロセスを開始し、サービスからの戻り値を待つ必要がない場合があります。 サービスに対して一方向の呼び出しを行う必要がある場合は、リスト 13 に示されているコールバック関数を省略するだけで済みます。 コールバック関数が定義されていないため、プロキシ オブジェクトは Web サービスがデータを返すのを待機しません。

エラーの処理

Web サービスへの非同期コールバックでは、ネットワークが停止している、Web サービスが使用できない、例外が返されるなど、さまざまな種類のエラーが発生する可能性があります。 幸いにも、ScriptManager によって生成された JavaScript プロキシ オブジェクトを使用すると、前に示した成功コールバックに加えて、エラーとエラーを処理するために複数のコールバックを定義できます。 エラー コールバック関数は、リスト 14 に示すように、Web メソッドの呼び出しで標準コールバック関数の直後に定義できます。

一覧 14. エラー コールバック関数を定義し、エラーを表示する。

function GetCustomersByCountry() 
{
     var country = $get("txtCountry").value;
     InterfaceTraining.CustomersService.GetCustomersByCountry(country, 
          OnWSRequestComplete, OnWSRequestFailed);
}
function OnWSRequestFailed(error)
{
     alert("Stack Trace: " + error.get_stackTrace() + "/r/n" +
          "Error: " + error.get_message() + "/r/n" +
          "Status Code: " + error.get_statusCode() + "/r/n" +
          "Exception Type: " + error.get_exceptionType() + "/r/n" +
          "Timed Out: " + error.get_timedOut());
}

Web サービスが呼び出されたときに発生するエラーは、エラーを表すオブジェクトをパラメーターとして受け入れる OnWSRequestFailed() コールバック関数が呼び出されるようにトリガーされます。 error オブジェクトは、エラーの原因と、呼び出しがタイムアウトしたかどうかを判断するために、いくつかの異なる関数を公開します。リスト 14 はさまざまなエラー関数を使用する例を示し、図 2 は関数によって生成される出力の例を示しています。

AJAX エラー関数 ASP.NET 呼び出すことによって生成される出力。

図 2: ASP.NET AJAX エラー関数を呼び出して生成された出力。 (クリックするとフルサイズの画像が表示されます)

Web サービスから返される XML データの処理

以前は、Web メソッドが ScriptMethod 属性とその ResponseFormat プロパティを使用して生の XML データを返す方法を確認しました。 ResponseFormat が ResponseFormat.Xml に設定されている場合、Web サービスから返されるデータは JSON ではなく XML としてシリアル化されます。 これは、JavaScript または XSLT を使用して処理するために XML データをクライアントに直接渡す必要がある場合に便利です。 現在、インターネット エクスプローラー 5 以降では、MSXML に対する組み込みのサポートにより、XML データの解析とフィルター処理に最適なクライアント側オブジェクト モデルが提供されています。

Web サービスから XML データを取得することは、他のデータ型を取得するのと同じ違いはありません。 まず、JavaScript プロキシを呼び出して適切な関数を呼び出し、コールバック関数を定義します。 呼び出しから戻ったら、コールバック関数のデータを処理できます。

リスト 15 は、XmlElement オブジェクトを返す GetRssFeed() という名前の Web メソッドを呼び出す例を示しています。 GetRssFeed() は、取得する RSS フィードの URL を表す 1 つのパラメーターを受け取ります。

一覧 15. Web サービスから返される XML データの操作。

function GetRss()
{
     InterfaceTraining.DemoService.GetRssFeed(
          "https://blogs.interfacett.com/dan-wahlins-blog/rss.xml",
          OnWSRequestComplete);
}
function OnWSRequestComplete(result)
{
     if (document.all) //Filter for IE DOM since other browsers are limited
     {
          var items = result.selectNodes("//item");
          for (var i=0;i<items.length;i++)
          {
               var title = items[i].selectSingleNode("title").text;
               var href = items[i].selectSingleNode("link").text;
               $get("divOutput").innerHTML +=
               "<a href='" + href + "'>" + title + "</a><br/>";
          }
     }
     else
     {
          $get("divOutput").innerHTML = "RSS only available in IE5+";
     }
}

次の使用例は、URL を RSS フィードに渡し、返された XML データを OnWSRequestComplete() 関数で処理します。 OnWSRequestComplete() は、まず、ブラウザーがインターネット エクスプローラーであるかどうかを調べ、MSXML パーサーが使用可能かどうかを確認します。 その場合、XPath ステートメントを使用して、RSS フィード内のすべての <アイテム> タグを検索します。 その後、各項目が反復処理され、関連 <するタイトル> タグと <リンク> タグが見つけられて処理され、各項目のデータが表示されます。 図 3 は、JavaScript プロキシを介して GetRssFeed() Web メソッドに ASP.NET AJAX 呼び出しを行った場合に生成される出力の例を示しています。

複合型の処理

Web サービスによって受け入れられる複合型または返される複合型は、JavaScript プロキシを介して自動的に公開されます。 ただし、入れ子になった複合型は、前述のように GenerateScriptType 属性がサービスに適用されない限り、クライアント側では直接アクセスできません。 クライアント側で入れ子になった複合型を使用する理由

この質問に答えるために、ASP.NET AJAX ページに顧客データが表示され、エンド ユーザーが顧客の住所を更新できるものとします。 Web サービスで Address 型 (CustomerDetails クラス内で定義された複合型) をクライアントに送信できることを指定した場合、更新プロセスを個別の関数に分割して、コードを再利用しやすくすることができます。

RSS データを返す Web サービスの呼び出しから作成される出力。

図 3: RSS データを返す Web サービスの呼び出しから作成する出力。 (クリックするとフルサイズの画像が表示されます)

リスト 16 は、Model 名前空間で定義されている Address オブジェクトを呼び出し、更新されたデータを入力して CustomerDetails オブジェクトの Address プロパティに割り当てるクライアント側コードの例を示しています。 その後、CustomerDetails オブジェクトが処理のために Web サービスに渡されます。

一覧 16. 入れ子になった複合型の使用

function UpdateAddress()
{
     var cust = new Model.CustomerDetails();
     cust.CustomerID = $get("hidCustomerID").value;
     cust.Address = CreateAddress();
     InterfaceTraining.DemoService.UpdateAddress(cust,OnWSUpdateComplete);
}
function CreateAddress()
{
     var addr = new Model.Address();
     addr.Street = $get("txtStreet").value;
     addr.City = $get("txtCity").value;
     addr.State = $get("txtState").value;
     return addr;
}
function OnWSUpdateComplete(result)
{
     alert("Update " + ((result)?"succeeded":"failed")+ "!");
}

ページ メソッドの作成と使用

Web サービスは、ASP.NET AJAX ページを含むさまざまなクライアントに再利用可能なサービスを公開する優れた方法を提供します。 ただし、他のページで使用または共有されることのないデータをページで取得する必要がある場合があります。 この場合、ページがデータにアクセスできるように .asmx ファイルを作成すると、サービスは 1 つのページでのみ使用されるため、やり過ぎのように見える可能性があります。

ASP.NET AJAX は、スタンドアロンの .asmx ファイルを作成せずに Web サービスのような呼び出しを行う別のメカニズムを提供します。 これは、"ページ メソッド" と呼ばれる手法を使用して行われます。 ページ メソッドは、WebMethod 属性が適用されたページまたはコードの横のファイルに直接埋め込まれた静的 (VB.NET で共有) メソッドです。 WebMethod 属性を適用することで、実行時に動的に作成される PageMethods という名前の特別な JavaScript オブジェクトを使用して呼び出すことができます。 PageMethods オブジェクトは、JSON シリアル化/逆シリアル化プロセスから保護するプロキシとして機能します。 PageMethods オブジェクトを使用するには、ScriptManager の EnablePageMethods プロパティを true に設定する必要があります。

<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
</asp:ScriptManager>

リスト 17 は、ASP.NET のコード側クラスで 2 つのページ メソッドを定義する例を示しています。 これらのメソッドは、Web サイトの App_Code フォルダーにあるビジネス レイヤー クラスからデータを取得します。

一覧 17. ページ メソッドの定義。

[WebMethod]
public static Customer[] GetCustomersByCountry(string country)
{
     return Biz.BAL.GetCustomersByCountry(country);
}
[WebMethod]
public static Customer[] GetCustomersByID(string id)
{
     return Biz.BAL.GetCustomersByID(id);
}

ScriptManager は、ページ内に Web メソッドが存在することを検出すると、前述の PageMethods オブジェクトへの動的参照を生成します。 Web メソッドの呼び出しは、PageMethods クラスの後にメソッドの名前と、渡す必要がある必要なパラメーター データを参照することによって実現されます。 リスト 18 は、前に示した 2 つのページ メソッドを呼び出す例を示しています。

一覧 18. PageMethods JavaScript オブジェクトを使用してページ メソッドを呼び出す。

function GetCustomerByCountry() 
{
     var country = $get("txtCountry").value;
     PageMethods.GetCustomersByCountry(country, OnWSRequestComplete);
}
function GetCustomerByID() 
{
     var custID = $get("txtCustomerID").value;
     PageMethods.GetCustomersByID(custID, OnWSRequestComplete);
}
function OnWSRequestComplete(results) 
{
     var searchResults = $get("searchResults");
     searchResults.control.set_data(results);
     if (results != null) GetMap(results[0].Country,results);
}

PageMethods オブジェクトの使用は、JavaScript プロキシ オブジェクトの使用とよく似ています。 最初に、ページ メソッドに渡す必要があるすべてのパラメーター データを指定してから、非同期呼び出しが返されたときに呼び出されるコールバック関数を定義します。 エラー コールバックを指定することもできます (エラーの処理例については、リスト 14 を参照してください)。

AutoCompleteExtender と ASP.NET AJAX Toolkit

ASP.NET AJAX Toolkit (から https://www.devexpress.com/Products/AJAX-Control-Toolkit使用可能) には、Web サービスへのアクセスに使用できるいくつかのコントロールが用意されています。 具体的には、ツールキットには という名前 AutoCompleteExtender の便利なコントロールが含まれています。このコントロールを使用すると、JavaScript コードをまったく記述せずに Web サービスを呼び出し、ページにデータを表示できます。

AutoCompleteExtender コントロールを使用すると、テキスト ボックスの既存の機能を拡張し、ユーザーが探しているデータをより簡単に見つけることができます。 テキスト ボックスに入力すると、コントロールを使用して Web サービスのクエリを実行し、テキスト ボックスの下に動的に結果を表示できます。 図 4 は、AutoCompleteExtender コントロールを使用してサポート アプリケーションの顧客 ID を表示する例を示しています。 ユーザーがテキスト ボックスに異なる文字を入力すると、入力に基づいて異なる項目が下に表示されます。 その後、ユーザーは目的の顧客 ID を選択できます。

ASP.NET AJAX ページ内で AutoCompleteExtender を使用するには、AjaxControlToolkit.dll アセンブリを Web サイトの bin フォルダーに追加する必要があります。 ツールキット アセンブリが追加されたら、そのアセンブリをweb.configで参照して、そのアセンブリに含まれるコントロールをアプリケーション内のすべてのページで使用できるようにします。 これを行うには、web.configの controls タグ内に次の <タグを> 追加します。

<add namespace="AjaxControlToolkit" assembly="AjaxControlToolkit" tagPrefix="ajaxToolkit"/>

特定のページでのみコントロールを使用する必要がある場合は、次に示すように、ページの上部に Reference ディレクティブを追加して、web.configを更新することで、コントロールを参照できます。

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" 
     TagPrefix="ajaxToolkit" %>

AutoCompleteExtender コントロールの使用。

図 4: AutoCompleteExtender コントロールの使用。 (クリックするとフルサイズの画像が表示されます)

ASP.NET AJAX Toolkit を使用するように Web サイトを構成したら、通常の ASP.NET サーバー コントロールを追加するのと同じように、AutoCompleteExtender コントロールをページに追加できます。 リスト 19 は、コントロールを使用して Web サービスを呼び出す例を示しています。

一覧 19. ASP.NET AJAX Toolkit AutoCompleteExtender コントロールを使用する。

<ajaxToolkit:AutoCompleteExtender ID="extTxtCustomerID" runat="server"
     MinimumPrefixLength="1" ServiceMethod="GetCustomerIDs"
     ServicePath="~/CustomersService.asmx"
     TargetControlID="txtCustomerID" />

AutoCompleteExtender には、サーバー コントロールで見つかった標準 ID プロパティや runat プロパティなど、いくつかの異なるプロパティがあります。 これらに加えて、Web サービスでデータのクエリを実行する前に、エンド ユーザーが入力した文字の数を定義できます。 リスト 19 に示されている MinimumPrefixLength プロパティを使用すると、テキスト ボックスに文字が入力されるたびにサービスが呼び出されます。 ユーザーが文字を入力するたびに、テキスト ボックス内の文字と一致する値を検索するために Web サービスが呼び出されるため、この値を慎重に設定する必要があります。 呼び出す Web サービスとターゲット Web メソッドは、それぞれ ServicePath プロパティと ServiceMethod プロパティを使用して定義されます。 最後に、TargetControlID プロパティは、AutoCompleteExtender コントロールをフックするテキスト ボックスを識別します。

呼び出される Web サービスには、前述のように ScriptService 属性が適用されている必要があり、ターゲット Web メソッドは prefixText と count という名前の 2 つのパラメーターを受け入れる必要があります。 prefixText パラメーターはエンド ユーザーが入力した文字を表し、count パラメーターは返す項目の数を表します (既定値は 10)。 リスト 20 は、リスト 19 で前に示した AutoCompleteExtender コントロールによって呼び出される GetCustomerIDs Web メソッドの例を示しています。 Web メソッドはビジネス レイヤー メソッドを呼び出し、データのフィルター処理と一致する結果の返しを処理するデータ レイヤー メソッドを呼び出します。 データ層メソッドのコードは、リスト 21 に示されています。

リスト 20。 AutoCompleteExtender コントロールから送信されたデータのフィルター処理。

[WebMethod]
public string[] GetCustomerIDs(string prefixText, int count) 
{
     return Biz.BAL.GetCustomerIDs(prefixText, count);
}

一覧 21. エンド ユーザーの入力に基づいて結果をフィルター処理する。

public static string[] GetCustomerIDs(string prefixText, int count)
{
     //Customer IDs cached in _CustomerIDs field to improve performance
     if (_CustomerIDs == null)
     {
          List<string> ids = new List<string>();
          //SQL text used for simplicity...recommend using sprocs
          string sql = "SELECT CustomerID FROM Customers";
          DbConnection conn = GetDBConnection();
          conn.Open();
          DbCommand cmd = conn.CreateCommand();
          cmd.CommandText = sql;
          DbDataReader reader = cmd.ExecuteReader();
          while (reader.Read())
          {
               ids.Add(reader["CustomerID"].ToString());
          }
          reader.Close();
          conn.Close();
          _CustomerIDs = ids.ToArray();
     }
     int index = Array.BinarySearch(_CustomerIDs, prefixText, new CaseInsensitiveComparer());
     //~ is bitwise complement (reverse each bit)
     if (index < 0) index = ~index;
     int matchingCount;
     for (matchingCount = 0; matchingCount < count && index + matchingCount < _CustomerIDs.Length; matchingCount++)
     {
          if (!_CustomerIDs[index + matchingCount].StartsWith(prefixText, StringComparison.CurrentCultureIgnoreCase))
          {
               break;
          }
     }
     String[] returnValue = new string[matchingCount];
     if (matchingCount > 0)
     {
          Array.Copy(_CustomerIDs, index, returnValue, 0, matchingCount);
     }
     return returnValue;
}

まとめ

ASP.NET AJAX は、要求メッセージと応答メッセージを処理する多くのカスタム JavaScript コードを記述せずに Web サービスを呼び出すための優れたサポートを提供します。 この記事では、.NET Web Services を AJAX で有効にして JSON メッセージを処理できるようにする方法と、ScriptManager コントロールを使用して JavaScript プロキシを定義する方法について説明しました。 また、JavaScript プロキシを使用して Web サービスを呼び出し、単純で複雑な型を処理し、エラーに対処する方法も確認しました。 最後に、ページ メソッドを使用して Web サービス呼び出しを作成および実行するプロセスを簡略化する方法と、AutoCompleteExtender コントロールが入力時にエンド ユーザーにヘルプを提供する方法について説明しました。 ASP.NET AJAX で使用できる UpdatePanel は、そのシンプルさのために多くの AJAX プログラマにとって確実に選択の制御になりますが、JavaScript プロキシを介して Web サービスを呼び出す方法を知ることは、多くのアプリケーションで役立ちます。

経歴

Dan Wahlin (Microsoft Most Valuable Professional for ASP.NET and XML Web Services) は、インターフェイス テクニカル トレーニング (http://www.interfacett.com) の .NET 開発インストラクターおよびアーキテクチャ コンサルタントです。 Dan は、INETA 講演者局にある ASP.NET 開発者向け XML Web サイト (www.XMLforASP.NET) を設立し、いくつかの会議で講演しています。 Dan 共同編集の Professional Windows DNA (Wrox)、ASP.NET: Tips、Tutorials and Code (Sams)、ASP.NET 1.1 Insider Solutions、Professional ASP.NET 2.0 AJAX (Wrox)、ASP.NET 2.0 MVP Hacks、authored XML for ASP.NET Developers (Sams)。 コード、記事、本を書かないとき、Danは妻と子供たちと一緒に音楽の書き込みと録音、ゴルフやバスケットボールを楽しんでいます。

Scott Cate は 1997 年から Microsoft Web テクノロジと協力し、myKB.com (www.myKB.com) の社長として、ナレッジ ベース ソフトウェア ソリューションに焦点を当てた ASP.NET ベースのアプリケーションの作成を専門としています。 Scott は、メールまたは自分のブログ ( scott.cate@myKB.com ScottCate.com) で連絡できます