jQuery から WCF サービスを呼び出すサンプルを [WCF4.0]WCFサービスをjQueryから呼び出す で記載しました。 ASP.NET Web サービス を jQuery から呼び出すプログラムを作成する機会があったので、その方法も覚書として記載します。

呼び出す Webサービス は WCF サービスを jQuiery から呼び出すときに使用した サンプルと基本的に同じです。

動作確認環境は次の通り

  • Visual Stusio 2010 Professional
  • .NET 4.0
  • IE9.0 標準モードで動作確認

サンプルでは NuGet パッケージマネージャーを使用するので インストールしておいてください。

1. サンプルプログラムの作成

Visual Studio 2010 空のWebアプリケーションプロジェクトを作成します。プロジェクトはここでは AsmxJQueryIntegration としました。

1.1 jQuery のインストール

メニューのツール→ライブラリパッケージマネージャー→パッケージマネージャーコンソール をクリックします。下図のように マネージャーコンソールから 次のコマンドを入力して jQuery をインストールします。

Install-Package jquery
GUIを使用して jQuery をインストールすることもできます。プロジェクトを右クリック→ NuGet パッケージの管理をクリックしてパッケージの管理画面を表示、オンラインを選択して、jQuery を検索してインストールすることもできます

1.2 ASP.NET Webサービスの作成

ASP.NET Web サービスを作成します。 新しい項目の追加画面で Web サービスを 選択します。下例では ProductService.asmx という名前で ASP.NET Web サービスを作成しています。

ProductServicw.asmx.cs ファイルを次のように編集します。System.Web.Script.Services名前空間 の ScriptService Attribute を使用して JSON 形式 で データの送受信を行うようにします。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services;

namespace AsmxJQueryIntegration
{
    /// <summary>
    /// ProductService の概要の説明です
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // この Web サービスを、スクリプトから ASP.NET AJAX を使用して呼び出せるようにするには、次の行のコメントを解除します。 
    [System.Web.Script.Services.ScriptService]
    public class ProductService : System.Web.Services.WebService
    {
        List<Product> products;
        public ProductService()
        {
            // 適当にサンプルデータ作成
            products = new List<Product>
            {
                new Product{ ProductId = 1, Name = "Car", UnitPrice=1000},
                new Product{ ProductId = 2, Name = "Bicycle", UnitPrice=40000},
                new Product{ ProductId = 3, Name = "Train", UnitPrice=5000000}
            };
        }
        // XmlSerializarはIEnumerable<Product> をシリアライズ
        // できないため List<Product> に変更しています
        [WebMethod]
        [ScriptMethod(UseHttpGet=true)]
        public List<Product> RetrieveAllProduct()
        {
            return products;
        }

        [WebMethod]
        public Product RetrieveProductByName(string name)
        {
            var query = from p in products
                        where p.Name == name
                        select p;

            return query.FirstOrDefault();
        }

        [WebMethod]
        public void AddProduct(Product item)
        {
            products.Add(item); // 特に意味のあるコードではない
        }
        [WebMethod]
        public void AddProducts(Product[] items)
        {
            foreach (var item in items)
            {
                products.Add(item);
            }
        }
        [WebMethod]
        public void UpdateProduct(int productId, string name, decimal price)
        {
            // do nothing
        }
    }
    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public decimal UnitPrice { get; set; }
    }

}

1.3 クライアント html ファイルの作成

作成した Webサービスを呼び出す html ファイルを作成します。新しい項目の追加画面で HTML ページ を選択してファイルを作成します。ここでは 名前を index.html としています。

html ファイルを次のように編集します。

<!DOCTYPE html>
<!-- IE8以上 標準モードで動作させることが前提 -->
<!-- Quirks(クアークス)モードで動作させる場合は json2.js がJSON.stringify/parse メソッドを使用するのに必要 -->
<html lang="ja">
<head>
    <title>ASMX jQuery Integration Sample</title>
    <script src="Scripts/jquery-1.8.1.js" type="text/javascript"></script>
    <script type="text/javascript">
        (function ($) {
            $(function () {
                // Getで取得するテスト
                $.ajax({
                    type: "Get",
                    datatype: "json",
                    url: "ProductService.asmx/RetrieveAllProduct",
                    data: null,
                    contentType: "application/json; charset=utf-8",
                    //                    beforeSend: function (xhr) {
                    //                        xhr.setRequestHeader("Accept", "application/json")
                    //                    },
                    success: function (data, textStatus, xhr) {
                        // data.d のように プロパティd経由でデータにアクセスする  
                        for (var i = 0; i < data.d.length; ++i) {
                            $("#list").append(data.d[i].ProductId).append(data.d[i].Name).append(data.d[i].UnitPrice);
                            $("#list").append("<br>");
                        }
                    },
                    error: function (xhr, textStatus, errorThrown) {
                        alert(xhr.responseText);
                    }
                });
                $("#retrieveByNameBtn").click(function () {
                    var obj = new Object();
                    obj.name = "Car";

                    var arg = JSON.stringify(obj);
                    $.ajax({
                        type: "Post",
                        datatype: "json",
                        url: "ProductService.asmx/RetrieveProductByName",
                        data: arg,
                        contentType: "application/json; charset=utf-8",
                        success: function (data, textStatus, xhr) {
                            if (data != null) {
                                $("#list").append(data.d.ProductId).append(data.d.Name).append(data.d.UnitPrice);
                                $("#list").append("<br>");
                            }
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            alert(xhr.responseText);
                        }
                    });
                });
                $("#addBtn").click(function () {
                    var obj = {
                        item: { Name: "NewName",
                            ProductId: 100
                        }
                    };

                    var arg = JSON.stringify(obj);
                    $.ajax({
                        type: "Post",
                        datatype: "json",
                        url: "ProductService.asmx/AddProduct",
                        data: arg,
                        contentType: "application/json; charset=utf-8",
                        beforeSend: function (xhr) {
                            xhr.setRequestHeader("Accept", "application/json")
                        },
                        success: function (data, textStatus, xhr) {
                            alert("Added");
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            alert(xhr.responseText);
                        }
                    });
                });
                $("#addMultipleBtn").click(function () {
                    var obj = { items: new Array(2) };
                    obj.items[0] = { Name: "NewName1", ProductId: 201, UnitPrice: 30 };
                    obj.items[1] = { Name: "NewName2", ProductId: 202, UnitPrice: 33 };

                    // 互換モードの場合は json2.js が必要
                    var arg = JSON.stringify(obj);
                    $.ajax({
                        type: "Post",
                        datatype: "json",
                        url: "ProductService.asmx/AddProducts",
                        data: arg,
                        contentType: "application/json; charset=utf-8",
                        success: function (data, textStatus, xhr) {
                            alert("Added");
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            alert(xhr);
                        }
                    });
                });
                $("#updateBtn").click(function () {
                    // 手動でjson形式の文字列を設定する場合
                    var arg = '{ "productId" : "20" , "name" : "UpdatedName" , "price":"20.0"}';
                    $.ajax({
                        type: "Post",
                        datatype: "json",
                        url: "ProductService.asmx/UpdateProduct",
                        data: arg,
                        contentType: "application/json; charset=utf-8",
                        beforeSend: function (xhr) {
                            xhr.setRequestHeader("Accept", "application/json")
                        },
                        success: function (data, textStatus, xhr) {
                            alert("Updated");
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            alert(xhr);
                        }
                    });
                });
            });
        }
        )(jQuery);
    </script>
</head>
<body>
   <div id="list">
    </div>
    <input type="button" id="retrieveByNameBtn" value="検索" />
    <input type="button" id="addBtn" value="追加" />
    <input type="button" id="addMultipleBtn" value="複数追加" />
    <input type="button" id="updateBtn" value="更新" />
</body>
</html>

ボタンをクリックすると ProductService.asmx の各メソッドを呼び出すようにしています。サンプルソースやデータをキャプチャして確認してもらえればわかりますが、Webサービスの結果を取得するさいに、 d プロパティをつけて実際の値にアクセスする必要があります。

互換モードで動作させる場合は JSON.stringify メソッドが存在しないので json2.js を別途ダウンロードして ページに含めるようにしてください。

2. 動作確認

Web アプリケーションをデバッグ実行して index.html を表示します。 検索ボタンをクリックすると RetrieveAllProduct が呼び出されます。

追加ボタンで 一覧の最後にデータが追加されます。 そのほか、 複数追加、更新ボタンを押すと Webサービスのメソッドが呼び出されます。

3.まとめ

説明は以上です。jQuery を使用して WCF サービスや ASP.NET Webサービス を統合できます。