WCFサービスではwebHttpBindingの構成を変更することでJSON形式で結果をシリアライズして、AJAXのクライアントに結果を返せるようになります。

確認環境は次の通り

  • Windows Vista Enterprise(WCFサービス,WCFクライアント同一マシン)
  • 開発環境 Visual Studio 2008 Professional (英語版)
  • .NET 3.5

1. ソリューションの作成

Visual Studioを起動して空のプロジェクトを作成します。プロジェクト名はWCFSample017としました。

2. WCFサービスプロジェクトの作成

ソリューションを右クリック→[Add]→[New Project]でプロジェクトを新規作成します。WCF Service Libraryテンプレートを選択して、プロジェクト名をWCFSample.PersonServiceとしてプロジェクトを新規作成します。プロジェクト作成後、自動で作成されたIService.cs,Service.cs,App.configを削除します。プロジェクトの参照にSystem.ServiceModel.Webを追加して、サービスクラス、データコントラクトを作成します。

2.1 データコントラクトクラスの作成

プロジェクトを右クリック→[Add]→[New Item]でファイルタイプにClassを選択、ファイル名をPerson.csとして作成する。

Person.csを次のように編集します。PersonクラスはID,ファーストネーム、ラストネームを持つデータコントラクトクラスです。

using System;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Runtime.Serialization;

namespace WCFSample.PersonService
{
    [DataContract]
    public class Person
    {
        public Person(int id, string firstName, string lastName)
        {
            this.ID = id;
            this.FirstName = firstName;
            this.LastName = lastName;
        }
        [DataMember]
        public int ID;
        [DataMember]
        public string FirstName = "";
        [DataMember]
        public string LastName = "";
    }
} 

2.2 サービスコントラクト,サービスクラスの作成

プロジェクトで新規項目を作成します。ファイルタイプのWCF Serviceを選択。ファイル名をPersonSearchと入力して、サービスコントラクト、サービスクラスを新規作成します。

サービスコントラクトクラスIPersonSearch.csは次のように編集します。ServiceContract.Namespaceに設定した値WCFSample.AjaxScriptは、AJAX用のクライアントスクリプトのネームスペースになります。

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace WCFSample.PersonService
{
    [ServiceContract(Namespace="WCFSample.AjaxScript")]
    interface IPersonSearch
    {
        [OperationContract]
        [WebGet]
        IList<Person> GetPersons();

        [OperationContract]
        [WebGet]
        Person GetPersonByID(int id);
    }
} 

サービスクラスは次のように編集します。

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;

namespace WCFSample.PersonService
{
    public class PersonSearch : IPersonSearch
    {
        #region IPersonSearch Members

        public IList<Person> GetPersons()
        {
            return persons;
        }
        // idに該当する情報を返す。
        public Person GetPersonByID(int id)
        {
            Person result  = (from p in persons 
                                    where p.ID == id
                                          select p).Single();

            return result;
            // 非LINQバージョン
            //foreach (Person p in persons)
            //{
            //    if (p.ID == id) return p;
            //}

            //throw new FaultException("Not Found");
        }

        #endregion

        private static IList<Person> persons = new List<Person>();
        static PersonSearch()
        {
            persons.Add(new Person(1, "aiueo", "AIUEO"));
            persons.Add(new Person(2, "kakikukeko", "KAKIKUKEKO"));
            persons.Add(new Person(3, "sashisuseso", "SASHISUSESO"));
        }
    }
} 

App.configが作成されている場合、使用しないので削除しておいて下さい。

3.ASP.NET サイトの作成

ソリューションを右クリック→[Add]→[New Web Site..]を選択して新規にWebサイトを作成します。ソリューション直下にWebSiteフォルダにプロジェクトを作成しました。ウェブサイトプロジェクトを右クリックして、プロジェクトの参照にWCFSample.PersonServiceを追加します。

3.1 サービスファイルの作成

ウェブサイトプロジェクトを右クリック→[Add New Item]をクリックします。表示されたAdd New Itemダイアログでファイルタイプにテキストを選択し、ファイル名service.svcとしてファイルを新規作成します。

作成されたsvcファイルでWCFSample.PersonService.PersonSearchサービスをホストできるように下のように編集します。

<%@ServiceHost language=c# Debug="true" Service="WCFSample.PersonService.PersonSearch" %>

Web.configを開いて次のようにwebHttpBindingを編集します。(system.serviceModelタグはconfigurationタグ直下に記述します。)endpoinBehaviorの設定でenableWebScriptを追加することで、WCFサービスで返されるデータがJSON形式でシリアライズされるようになります。バインディングはwebHttpBindingを使用します。

<system.serviceModel>
  <behaviors>
    <endpointBehaviors>
      <behavior name="WCFAjaxBehavior">
        <enableWebScript />
      </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
      <behavior name="ServiceBahavior">
        <serviceDebug includeExceptionDetailInFaults="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <services>
    <service name="WCFSample.PersonService.PersonSearch" behaviorConfiguration="ServiceBahavior">
	<endpoint address="" behaviorConfiguration="WCFAjaxBehavior" binding="webHttpBinding" bindingConfiguration="" name="WCFAjaxEndpoint" contract="WCFSample.PersonService.IPersonSearch"/>
    </service>
  </services>
</system.serviceModel>

3.2 ASP.NETテストページの作成

ウェブサイトプロジェクトを右クリック→[Add New Item]をクリックします。新規アイテムの追加でファイルタイプにAjax Web Fromを選択し、ファイル名をShowPerson.aspxとしてASP.NETのページを作成します。作成した画面をソースビューで開いて次のように編集します。ScriptManagerタグでサービスの参照を設定することで、PersonService用のAJAXクライアントのプロキシクラスが作成されるようになります。

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ShowPerson.aspx.cs" Inherits="ShowPerson" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test Page</title>

    <script type="text/javascript">
    
      function pageLoad() {
      }
    
      function ShowPersons(){
        var proxy = new WCFSample.AjaxScript.IPersonSearch();
        proxy.GetPersons(onSuccess, onFail, null);
      }
      function ShowPersonByID(){
        var idx = document.getElementById("searchID").selectedIndex;
        var option = document.getElementById("searchID")[idx].text;
        var proxy = new WCFSample.AjaxScript.IPersonSearch();
        proxy.GetPersonByID(parseInt(option), onSuccess2, onFail,  null);
        
      }
      function onSuccess(result){
        var tbdy = document.getElementById("searchresult");

        while(tbdy.childNodes.length > 0){
            tbdy.deleteRow(0);
        }

        var i;
        for(i=0;i<result.length;++i){
            var row = document.createElement("tr");
            var cell = document.createElement("td");
            row.appendChild(cell);
            cell.appendChild(document.createTextNode(result[i].ID));
            cell = document.createElement("td");
            row.appendChild(cell);
            cell.appendChild(document.createTextNode(result[i].FirstName));
            cell = document.createElement("td");
            row.appendChild(cell);
            cell.appendChild(document.createTextNode(result[i].LastName));
            tbdy.appendChild(row);
        }
        //alert(tbdy.innerHTML); // debug
      }
      function onFail(err){
        alert("ERROR");
      }
      function onSuccess2(result){
        var tbdy = document.getElementById("searchresult");
        while(tbdy.childNodes.length > 0){
            tbdy.deleteRow(0);
        }
        var row = document.createElement("tr");
        var cell = document.createElement("td");
        row.appendChild(cell);
        cell.appendChild(document.createTextNode(result.ID));
        cell = document.createElement("td");
        row.appendChild(cell);
        cell.appendChild(document.createTextNode(result.FirstName));
        cell = document.createElement("td");
        row.appendChild(cell);
        cell.appendChild(document.createTextNode(result.LastName));
        tbdy.appendChild(row);

        //alert(tbdy.innerHTML); // debug
      }
    </script>

</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
            <Services>
                <asp:ServiceReference Path="~/service.svc" />
            </Services>
        </asp:ScriptManager>
    </div>
    <table>
        <thead>
            <tr>
                <td>
                    ID
                </td>
                <td>
                    FirstName
                </td>
                <td>
                    LastName
                </td>
            </tr>
        </thead>
        <tbody id="searchresult">
        </tbody>
    </table>
    <input type="button" onclick="javascript:ShowPersons()" value="Search All" />
    <select id="searchID">
        <option>1</option>
        <option>2</option>
        <option>3</option>
    </select>
    <input type="button" onclick="javascript:ShowPersonByID()" value="Search By ID" />
    </form>
</body>
</html>

色が青色の文字が追加した部分です。javascriptでWebフォームのボタンがクリックしたときにAJAX用のプロキシクラスWCFSample.AjaxScriptを使用して、Personデータを取得するスクリプトを記述しています。Webフォームのページ部分の追加内容はデータ取得イベント用のボタンと取得結果表示用のtableです。WCFSample.AjaxScriptはサービスコントラクトで設定したNameSpaceに一致します。(JavaScriptの稚拙さはご容赦ください。あまり得意ではないのです。)

4.動作確認

プロジェクトを保存してデバッグ実行してみます。[Search All]ボタンを押すと次のように表示されます。

 

 

[Search By ID]ボタンを押すと、次のようになります。

 

 

IPersonServiceサービスコントラクトの定義でサービスオペレーションにWebGetAttributeを付与しているので、次のようにURLに打ち込むとJSON形式のデータを直接取得できます。ホスト名,ポート番号はよって変換して下さい。

http://localhost:49397/WebSite/service.svc/GetPersonByID?id=1

URLに直接入力すると、ファイルダウンロードダイアログが表示されるので、保存すると次のようにJSON形式でシリアライズされているデータを確認できます。

{"d":{"__type":"Person:#WCFSample.PersonService","FirstName":"aiueo","ID":1,"LastName":"AIUEO"}}

説明は以上です。間違い、指摘事項がありましたら連絡ください。

2011/6/14 追記

動作するサンプルがほしいという方がいたので、ソリューションを公開します。ここからダウンロードしてください。