CodeZine(コードジン)

特集ページ一覧

Visual Studio 2008で標準搭載されたWindows Communication Foundation

Visual Studio 2008 徹底入門 (7)

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/04/25 00:00

前回に続き、.NET Framework 3.0から導入されたコンポーネントとVisual Studio 2008でのサポートについて解説していきます。今回扱うのは通信フレームワークであるWCF(Windows Communication Foundation)です。.NET Framework 3.5でさまざまな新機能が追加され、より実用的なサービスの提供が可能となりました。

はじめに

 前回に続き、.NET Framework 3.0から導入されたコンポーネントとVisual Studio 2008でのサポートについて解説していきます。今回扱うのは通信フレームワークであるWCF(Windows Communication Foundation)です。.NET Framework 3.5でさまざまな新機能が追加され、より実用的なサービスの提供が可能となりました。

対象読者

  • VS 2008に興味がある方
  • WCFに興味がある方
  • .NET技術でのWebサービス構築に興味がある方

必要な環境

 シリーズ第1回を参考に、Visual Studio 2008のインストールを行ってください。

WCFについて

 WCFは.NET Framework 3.0で導入された統合通信フレームワークです。

 WCF導入前に存在したさまざまな通信フレームワークは、相互に互換性が無く、通信方式を簡単に差し替えることはできませんでした。例えば、.NETコンポーネント間で使われているTCPベースの.NET Remotingで構築したアプリケーションを、SOAPベースのWebサービスに対応させようとするなら、通信部分について、多くの書き換えが必要になっていました。

 WCFはこうした複数の通信フレームワークを統合しており、共通のアプローチで複数の通信方式を扱うことができます。

具体的には

 やや抽象的な話になってしまいましたが、具体的にはどんな効能があるのでしょうか。WCFはRPC(Remote Procedure Call:遠隔手続呼出)の一種であり、ネットワークを介してアプリケーション同士がお互いの公開する処理を相互に呼び出すための仕組みです。

 これでもまだ抽象的です。「アプリケーション同士」とか「お互いの公開する処理」といった部分は、具体的には何を指すのでしょうか? 一番身近に感じられるWCFのユースケースは「WebサーバとWebブラウザ」あるいは「Webサーバ同士」が、「Webサービス」を公開する/呼び出すために使用する、というものでしょう。

WCFの他のユースケース
 もちろんWCFはWebに依存しない汎用通信フレームワークですので、他にも次のようなさまざまなユースケースがあります。
  • エンタープライズシステムで、Microsoft Message Queuingを使ったメッセージキューサービスを使用するため
  • P2P(Peer to Peer)通信をサポートするため
  • .NET Remotingで相互通信を行っていたアプリケーションをWCFベースの処理に移行するため
WCFにはWebに限定されない広範な用途があることを踏まえつつ、本記事では最も使われるであろう、Webサービスに関連したテーマで活用方法を説明していきます。

 .NET Framework 3.0では、SOAPベースのXML Webサービスのみがサポートされていましたが、.NET Framework 3.5の新機能として、WCF Webプログラミング モデルがサポートされ、SOAPを使わない簡潔な方式の、いわゆる「RESTスタイル」のWebサービスや、AJAXでしばしば用いられるJSON(JavaScript Object Notation)形式のサポート、RSS/ATOMを使った配信のサポートなどが追加され、Webサービスの構築において、より実際的なフレームワークとなりました。

REST?POX?
 MSDNではRESTスタイルのWebサービスのことを、「POX(Plain Old XML)スタイルのWebサービス」と呼ぶ場合があります。本記事では一般的に受け入れられている「REST」を用語として用います(MSDNではRESTという用語も用いられています)。
RESTの定義はさまざまありますが、本記事では次のような条件を満たすサービスをRESTスタイルのWebサービスとして扱います。
  • ステートレスな(状態を持たない)プロトコル
  • すべてのリソースはURIで一意に表される
  • HTTPの基本操作(GET/PUT/DELETEなど)を用いる
  • SOAPのようにメッセージの厳密な抽象化を行わず、XMLを直接扱う

 本記事では、WCFの基本概念を説明した後に、SOAPベースのWebサービスの公開、RESTスタイルのWebサービスの公開、JSON形式のサポートなどのサンプルを見ていきます。

 特に、WCFでWebサービスを提供することを主眼に記事を進めていきますので、WCFでクライアント側の処理を実装する部分については省略します。

WCFについての他の記事
 WCFを使ったTCPベース通信のサンプルや、WCFを使ったクライアント実装については、Visual Studio 2005 + WCF Extensionsの解説記事を参照してください。

WCFがサポートする通信方式

 WCFは特定の通信方式に依存しないフレームワークで、現在のところ以下の通信方式をサポートしています。

WCFで使用可能な通信方式
通信方式 概要 相互運用性
TCP TCP/IPベースのテキスト/バイナリ通信 WCFコンポーネント
HTTP HTTPベースで、SOAPを使ったXML Web Services(Basic-ProfileないしはWebサービス拡張仕様)や、RESTスタイルのWebサービス、JSONなどをサポート Webサービス(SOAP/REST/JSONなど)をサポートするアプリケーション
名前付きパイプ 名前付きパイプを使用する通信方式 同一マシン内のWCFコンポーネント同士
MSMQ Microsoft Message Queuingを使用する通信方式 WCFコンポーネント/MSMQをサポートするアプリケーション
Peer to Peer Windows Peer-to-Peer Networkingを使用する通信方式 WCFコンポーネント

 さまざまな通信方式がサポートされていますが、相互運用性の観点からすると、HTTPベースのWebサービスを使うケースが多いでしょう。WCFを使えば、必要に応じて以上の通信方式を切り替える、ないしは共存させることができます。

 WCFはABC(Address , Binding , Contract)という基本的な概念を導入することで、通信方式とロジックの分離を図り、通信方式の切り替えを容易にしています。

 まずはこれらの概念を確認しておきましょう。

WCFのキーワード:ABC(+Bv)=E

 WCFの基本的な概念を表すキーワードが「ABC(+Bv)=E」です。

 ABC(+Bv)は「どこで(A:Address)、どのように(B:Binding , Bv:Behavior)、何を(C:Contract)」提供するかを表すキーワードの集合です。これらで構成されたサービスの提供口をエンドポイント(E:Endpoint)と呼びます。

WCFのキーワード 「ABC(+Bv)=E」
頭文字 キーワード 意味
A Address サービスを提供する場所
B Binding サービスで使用するデータの表現形式
C Contract サービス内容の定義
Bv Behaivor サービスの細かな挙動
E Endpoint ABC(+Bv)で構成されたサービスの提供口

 それぞれのキーワードについて説明していきましょう。

A:Address

 「どこでサービスを提供するか」を表すAはAddress(アドレス)の略で、サービスを提供するURIを表します。WCFサービスを利用するクライアントはこのURIに対してリクエストを発行することになります。

 以下にアドレスの例を示します。

通信方式ごとのURIの例
使用する通信方式 URI
HTTP http://somehost:8080/BasicService
TCP net.tcp://somehost:8081/TcpService
名前付きパイプ net.pipe://somehost/NamedPipeService

 本記事で解説するWebサービスの場合は、HTTP/HTTPSプロトコルを使ったURIがAddressとなります。

 

B:Binding

 「どのようにサービスを提供するか」を表すBはBinding(バインディング)の略で、データの表現形式を表します。

 例えば、同じHTTPプロトコルを使用する中でも、SOAPベースのWebサービスとRESTベースのWebサービスとJSONベースのWebサービスでは、同じデータを異なる表現形式で表すことになります。つまり、AddressだけではHTTPプロトコルだ、ということしか分かりませんので、それに加えて、HTTPプロトコル上でどのようにデータを表現するか、を表すのがこのバインディングです。

 WCFでは、次のようなバインディングが提供されています。

WCF標準のバインディング
バインディング名 概要
netTcpBinding TCP/IPを使用するバインディング
basicHttpBinding SOAPベースのWebサービスのBasic-Profileを使用するバインディング
wsHttpBinding Webサービス拡張仕様を使用するバインディング
netNamedPipeBinding 名前付きパイプを使用するバインディング
netMsmqBinding MSMQを使用してWCFコンポーネントと接続するためのバインディング
webHttpBinding RESTスタイルのWebサービスおよびJSONをサポートするWebプログラミングモデルのバインディング

 Visual Studio 2008でWCFを使ったプロジェクトを作成すると、SOAPベースのWebサービスを提供するbasicHttpBindingがデフォルトで使用されます。.NET Framework 3.5からサポートされたWebプログラミングモデルに対応するwebHttpBindingを使用すれば、RESTスタイルのWebサービスやJSONをサポートすることができます。

 なお、Webプログラミングモデルを使用する場合にはセキュリティに関する注意点があります。

 basicHttpBindingやwsHttpBindingなど、SOAPベースのBindingでは、WS-Securityを含むWS-*(Webサービス拡張仕様)に基づくセキュリティを使用することができます。しかし、SOAPを使用しないWebプログラミングモデルでは、SOAPヘッダーがないため、特別なセキュリティ情報を付加することができません。webHttpBindingを使ったWebプログラミングモデルの場合、AddressにHTTPSプロトコルを指定することで、暗号化のみを行うことができます。

C:Contract

 「何をサービスとして提供するか」を表すCはContract(コントラクト)の略で、実際にWCFを介してやり取りするデータを定義します。

 WCFのコントラクトには以下の2種類があります。

WCFのコントラクト
種類 概要
サービス・コントラクト サービスを提供するクラス・インターフェイスの定義
データ・コントラクト やり取りするデータについての定義
メッセージについてのコントラクト
 厳密には、WCFでやり取りするデータを定義するコントラクトには、データ・コントラクト以外にいくつかの方式(SOAPメッセージ構造を直接定義するメッセージ・コントラクトなど)があります。詳細はMSDNのドキュメントをご覧ください。

 コントラクトは、サービスを定義した.NETのクラス・インターフェイスに対し、属性として付加します。ここで重要な点ですが、コントラクトは通信方式やデータの表現形式には依存せず、公開するクラス・インターフェイス・メソッド・データがどれであるのか、WCFに通知する役割を担っています。

 今回のサンプルで使用するコントラクトを見てみましょう。最初はサービス・コントラクトですが、サービスを提供するIService1インターフェイスにServiceContract属性が、インターフェイス内の実際の操作を表すGetMessageメソッドにOperationContact属性がそれぞれ付加されています。WCFはServiceContract属性の付加されたクラス・インターフェイスを、サービスとして公開するクラス・インターフェイスとして、OperationContract属性の付加されたメソッドを実際のサービスとして認識し、外部に公開します。

IService1.cs サービス・コントラクト定義
[ServiceContract]
public interface IService1
{
  [OperationContract]
  string GetMessage(string name);
・・・中略・・・
}

 次に、データ・コントラクトを見てみましょう。intstringといった、.NET Frameworkの基本データ型については、特に定義することなく使用することができますが、独自のクラスについては、データをどのように受け渡す必要があるのかをWCFに通知する必要があり、これをデータ・コントラクトと呼びます。データ・コントラクトもサービス・コントラクトと同様に属性として表現します。

 以下のサンプルでは、独自のクラスであるAddressBookEntryクラスにDataContract属性が、受け渡す必要のあるデータであるId/NameプロパティにDataMember属性が付加されています。これにより、WCFはAddressBookEntryクラスのインスタンスがやり取りされる際に、そこに含まれるデータを適正に受け渡すことができます。

IService1.cs データ・コントラクト定義
[DataContract]
public class AddressBookEntry
{
  int id;
  string name;

  [DataMember]
  public int Id
    {
      get { return id; }
      set { id = value; }
    }

  [DataMember]
    public string Name
      {
        get { return name; }
        set { name = value; }
      }

・・・中略・・・

Bv:Behavior

 サービスの細かな挙動を表すBvはBehavior(ビヘイビア)の略です。WCFサービスのサーバ・クライアントで共有する必要がない、細かな設定情報が含まれています。

 複数のエンドポイントを含むサービス全体に対する設定を行う、サービス・ビヘイビアと、エンドポイントごとの設定を行う、エンドポイント・ビヘイビアが存在します。

E:Endpoint

 EはEndpoint(エンドポイント)の略で、ここまで説明したABC(+Bv)で構成されるサービスの提供口、ソケットのような概念を表します。

 WCFサービスを利用するクライアントは、このエンドポイントに対してサービスのリクエストを行います。つまり、

  • 通信先としてAで指定されたアドレスに
  • データ表現形式としてBで指定されたバインディングを使い
  • サービスの定義としてCで指定されたコントラクトに基づいて

 リクエストする、というわけです。

 このエンドポイントはサービス内に複数持つことができ、同じコントラクトに基づいて、異なるアドレス(通信方式)や、異なるバインディングを持つエンドポイントを同時に提供することもできます。

WCFの基本概念図
WCFの基本概念図

WCFのホスティング

 WCFはABC(+Bv)で構成されるエンドポイントをクライアントに向けて提供しますが、以下の2種類のホスティング形態を持っています。

  • アプリケーションによるホスティング
  • IISによるホスティング(開発時はVisual Studioの提供するASP.NET 開発サーバ)

 アプリケーションによるホスティングでもHTTPベースのWebサービスを提供することができますが、一般的な用途を考え、本記事ではIISによるWebサービスのホスティングを使用します。

ABC(+Bv)の指定方法

 エンドポイントを構成するABC(+Bv)のうち、C(コントラクト)については、ソースコード中に属性として記述することを既に解説しました。それ以外のAB(+Bv)については、以下の2種類の指定方法があります。

  • ソースコードで指定
  • XMLベースの設定ファイルで指定

 後者のXMLベースの設定ファイルは、.NET標準の構成ファイル(WindowsアプリケーションではApp.config、Webアプリケーションの場合はWeb.config)を使用します。本記事ではIISによるホスティングを使用しますので、ABCはWeb.configファイルで設定します。

 以下に実際の記述例を示します。

Web.configファイルにおけるABCの指定例
<configuration>
・・・中略・・・
  <system.serviceModel>
  <services>
   <service behaviorConfiguration="WcfServiceTest.Service1Behavior"
name="WcfServiceTest.Service1">
<endpoint address="" binding="basicHttpBinding"
bindingConfiguration=""
name="" contract="WcfServiceTest.IService1" />
</service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfServiceTest.Service1Behavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>

 中ほどにあるendpoint要素のaddress/binding/contract属性が、それぞれABCを指しています。

 IISによるホスティングを使用する場合、アドレスはHTTPプロトコルベースで、IIS側で割り当てられます。ここではbinding属性にSOAPベースのWebサービスであるbasicHttpBindingを、contract属性としてServiceContract属性を付加した、先ほどのWcfServiceTest.IService1インターフェイスを指定しています。

 さて、前置きが非常に長くなりましたが、WCFの基本概念を押さえることができたでしょうか。WCFサービスのキーワードであるABCをしっかり押さえつつ、サンプル作成に入っていきましょう。

 

サンプル1:SOAPスタイルのWebサービス

 まず最初にWCFのデフォルトである、SOAPスタイルのWebサービスのサンプルから作成しましょう。

 今回のサンプルでは、入力された文字列に挨拶メッセージを返すGetMessageと、ID・名前・住所を持つアドレス帳のエントリを返すGetAddressBookEntryの2つのサービスを提供します。サービス内容はシンプルなものですが、どのようにサービスを公開することができるのか、WCFを使った流れを把握しましょう。

プロジェクトの作成

 Visual Studio 2008を起動し、新しいプロジェクトを作成します。今回は[Visual C#]-[Web]カテゴリから[WCFサービス アプリケーション]を選択し、「WcfServiceTest」という名前でプロジェクトを作成します。

新しいプロジェクトの選択
新しいプロジェクトの選択

 新しいプロジェクトを作成すると、自動的にいくつかのファイルが作成されます。

自動生成されるファイル一覧(抜粋)
ファイル名 概要
IService1.cs 公開するサービスのインターフェイス定義。サービス・コントラクトとデータ・コントラクトが記されている。
Service1.svc 公開されるWCFサービスのエントリポイント。
Service1.svc.cs サービスの実装コード。IService1インターフェイスを実装したService1クラスが記されている。
Web.config XMLベースの設定ファイル。WCFで提供するサービスの設定が記されている。

 まず「Service1.svc」を見てみましょう。

Service1.svc
<%@ ServiceHost Language="C#" Debug="true"
    Service="WcfServiceTest.Service1" CodeBehind="Service1.svc.cs" %>

 内容はシンプルで、どのサービスを提供するかを定義しているだけです。今回は自動生成されたファイルにサービスを実装していきますので、このファイルは特に変更しません。このファイルがエントリポイントとなって、サービスを受け付けることになる、という点を押さえておきましょう。

コントラクトの定義

 では、最初にコントラクトを定義します。「IService1.cs」を開き、以下の内容に書き換えてください。

IService1.cs サービス・コントラクト定義
[ServiceContract]
public interface IService1
{
  [OperationContract]
  string GetMessage(string name);

  [OperationContract]
  AddressBookEntry GetAddressBookEntry(string id);
}

[DataContract]
public class AddressBookEntry
{
  int id;
  string name;
  string address;

  [DataMember]
  public int Id
    {
      get { return id; }
      set { id = value; }
    }

  [DataMember]
    public string Name
      {
        get { return name; }
        set { name = value; }
      }

  [DataMember]
    public string Address
      {
        get { return address; }
        set { address = value; }
      }
}

 外部に公開する2つのメソッドのインターフェイス定義と、そこで使用するデータに対して、属性を付加しています。各属性の意味はコントラクトの項で説明した通りです。

サービスの実装

 次に「Service1.svc.cs」を開き、サービスの実装コードを記します。

Service1.svc.cs
public class Service1 : IService1
{

  public string GetMessage(string name)
    {
      return string.Format("Hello {0}!", name);
    }

  public AddressBookEntry GetAddressBookEntry(string id)
    {
      int idvalue = int.Parse(id);
      AddressBookEntry entry;
      switch (idvalue)
        {
        case 1:
          entry = new AddressBookEntry() {
              Id = 1, Name = "Doi", Address = "Tokyo" };
          break;
        default:
          entry = new AddressBookEntry() {
              Id = 0, Name = "Anonymous", Address = "?" };
          break;
        }
      return entry;
    }
}

 実装自体は特別な内容ではなく、GetMessageメソッドは入力された名前にあいさつを付加した文字列を返し、GetAddressBookEntryメソッドはアドレス帳の項目を返します。本来であればGetAddressBookEntryメソッドには、データベースにアクセスするなどの処理が含まれることでしょう。実装クラスにWCFに依存した内容がまったく含まれないことに注目してください。

ABCの定義

 次に、このサービスで使用するABCの指定を行います。

 Web.configファイルを直接編集することもできますが、Visual Studio 2008にはMicrosoft Service Configuration Editorという、WCFの設定項目をGUIで編集するツールが付属していますので、これを利用することにしましょう。

 [ツール]-[WCF Service Configuration Editor]を選択し、[File]-[Open]よりWcfServiceTestプロジェクトのWeb.configファイルを開きます。

Microsoft Service Configuration Editorのデフォルトフォルダ
 Microsoft Service Configuration Editorを起動したら自動的にVisual Studio 2008で開いているプロジェクトの設定ファイルを読み込んでほしいところですが、現在のところはそこまでの連係は図られていません。また、「ファイルを開く」ダイアログのデフォルトフォルダも開いているプロジェクトとは無関係なフォルダが指定されます。
複数のプロジェクトでMicrosoft Service Configuration Editorを使用する場合、間違って異なるプロジェクトの設定ファイルを開かないよう注意してください。

 設定ファイルを開くと、次のような画面が表示されます。

WCFの設定内容
WCFの設定内容

 右下に2つのエンドポイントが表示されています。下はメタデータ取得のためにVisual Studio 2008が自動的に作成するエンドポイントですので無視してください。

 上のエンドポイントが今回使用するものです。

  • Addressは空
  • BindingはSOAPベースのbasicHttpBinding
  • ContractはWcfServiceTest.Iservice1インターフェイス

 となっています。今回は変更の必要はありませんので、[File]-[Exit]から終了させましょう。

サンプルの実行

 [F5]キーを押してサービスを実行してみましょう。最初に1回、デバッグを有効にするかどうかについてのダイアログが表示されますので、[OK]ボタンを押してください。

デバッグ有効/無効化ダイアログ
デバッグ有効/無効化ダイアログ

 Webブラウザが起動し、次のようなサービス画面が表示されるはずです。

Service1サービス ブラウザ画面
Service1サービス ブラウザ画面

 画面中のリンクをクリックすると、WebサービスのWSDL定義を閲覧することができます。この時点でWCFによるSOAPベースのWebサービスは完成し、クライアントのリクエストを受け付けることができます。実際にクライアントを作成してみましょう。

IISへのホスティング

 クライアント作成の前に、IISへのホスティングを行っておきます。これはASP.NET開発サーバではポート番号が不定のため、クライアントから接続するサービスを提供するには不都合なためです。

 WcfServiceTestプロジェクトの上で右クリックし、[発行]を選択します。

プロジェクトの発行
プロジェクトの発行

 「Webの発行」ダイアログで、右の[...]ボタンを押します。

「Webの発行」ダイアログ
「Webの発行」ダイアログ

 「Webサイトを開く」ダイアログで、左側の[ローカルIIS]をクリックします。右上の[新しいWebアプリケーションの作成]ボタンを押して新しいWebアプリケーション(ここではWcfTestとした)を作成し、[開く]ボタンを押します。

「Webサイトを開く」ダイアログ
「Webサイトを開く」ダイアログ

 「Webの発行」ダイアログで[発行]ボタンを押します。

「Webの発行」ダイアログ
「Webの発行」ダイアログ

 これでIISへのホスティングが完了しました。実際にアクセスして確かめてみましょう。

http://localhost/WcfTest/Service1.svc

 にアクセスし、先ほどと同じ画面が表示されることを確認してください。

Service1サービス ブラウザ画面
Service1サービス ブラウザ画面

クライアントの作成

 では、IISで公開されたWCFによるSOAPベースのWebサービスを、クライアントから呼び出してみましょう。SOAPベースのWebサービスはクライアントの種類を問いませんが、今回はWindows Formアプリケーションから呼び出してみます。

 [ファイル]-[追加]-[新しいプロジェクト]から[Visual C#]-[Windows]カテゴリの[Windowsフォーム アプリケーション]を選択し、新規プロジェクトを追加します。今回はプロジェクト名を「ClientTest」としました。

 Webサービスを呼び出すため、[プロジェクト]-[サービス参照の追加]から、先ほどのURIを指定して参照の追加を行います。

「サービス参照の追加」ダイアログ
「サービス参照の追加」ダイアログ

 左側のサービスペインでIService1を選択すると、右側に公開された操作が表示されます。[OK]ボタンを押すと、サービスを利用するための参照クラスが生成されます。

 フォームにボタンとラベルを配置し、ボタンをダブルクリックしてイベントハンドラを記述します。

クライアント フォーム
クライアント フォーム

 イベントハンドラ内で、WCFサービスを呼び出す処理を行います。

WCFサービス呼び出し処理
private void button1_Click(object sender, EventArgs e)
{
  ServiceReference1.IService1 service
      = new ServiceReference1.Service1Client();
  ServiceReference1.AddressBookEntry entry
      = service.GetAddressBookEntry("1");
  label1.Text = string.Format("ID={0} ,
      Name={1} , Address={2}", entry.Id, entry.Name, entry.Address);
}

 自動生成されたServiceReference1.Service1Clientクラスを使い、IService1インターフェイスを介して、IISでホスティングされているGetAddressBookEntryメソッドを呼び出し、結果をラベルに表示します。

 ClientTestプロジェクトをスタートアップ プロジェクトに指定し、[F5]キーを押して実行してみましょう。正しくサービスが公開されていれば、次のように、アドレス帳の項目が表示されるはずです。

WindowsフォームからのWebサービス呼び出し
WindowsフォームからのWebサービス呼び出し

 以上の手順でSOAPベースのWebサービスを作成し、呼び出しを確認することができました。ABCを適切に設定すれば、簡単にWebサービスを公開することができます。

 

サンプル2:RESTスタイルのWebサービス

 SOAPベースのWebサービスは、厳密なXML定義を扱う関係上、前項のサンプル作成を見ても分かるとおり、クライアント実装においてもそれなりの手順を踏む必要があります。Visual Studioを使って参照クラスを自動生成すれば手順は簡略化できますが、Ajaxなどで簡単にアクセスするには敷居が高いと言えます。開発者としても、ブラウザで簡単に内容を確認できないのは歯痒いところです。

 こうした問題点を受け、近年のWebサービスの潮流は、SOAPベースのものから、データを抽象化せず、直接XMLを扱うRESTスタイルのサービスへと向かいつつあります。

 では、.NET Framework 3.5でサポートされたWebプログラミングモデルを使い、RESTスタイルのWebサービスを作成してみましょう。

変更の流れ

 SOAPベースのWebサービスから、RESTスタイルのWebサービスに変更するには、以下の手順を踏みます。

  1. エンドポイントの設定変更
  2. まず、バインディングをSOAPベースのbasicHttpBindingから、WebプログラミングモデルのwebHttpBindingに変更します。また、サービスビヘイビアとして、Webプログラミングモデルに必要なwebHttpというビヘイビアを追加します。
     
  3. HTTP GETのURIテンプレート指定
  4. RESTスタイルのWebサービスの場合、クライアントはHTTP GETを使ってリクエストを行います。その際に、パラメータをURIのどの部分で表すかをテンプレートとして記述します。

エンドポイントの設定変更

 まずはABCの書き換えです。Microsoft Service Configuration Editorを起動し、WcfServiceTestプロジェクトのWeb.configファイルを開きましょう。

 左上のConfigurationペインで[Advanced]-[Endpoint Behaviours]をクリックし、右上の[New Endpoint Behaviour Configuration]をクリックします。

エンドポイント・ビヘイビアの追加
エンドポイント・ビヘイビアの追加

 [Add]ボタンを押し、ビヘイビア一覧ダイアログから[webHttp]を選択して[Add]ボタンを押します。

webHttpビヘイビアの追加
webHttpビヘイビアの追加

 左上のConfigurationペインで[Services]-[WcfServiceTest.Service1]-[Endpoints]-[(Empty Name)]の下のアイテムをクリックします。ちなみに上のアイテムは前述のメタデータ交換用のエンドポイントです。

 右ペインの[Behaviour Configuration]に先ほど作成したwebHttpBehaviorを、[Binding]にwebHttpBindingを指定します。

エンドポイント設定変更
エンドポイント設定変更

 これで、エンドポイントをSOAPベースからRESTスタイルのWebサービスに切り替えることができました。

HTTP GETのURIテンプレート指定

 SOAPベースのWebサービスの場合、サービスのパラメータはPOSTで指定しますが、RESTスタイルのWebサービスの場合は、パラメータをHTTP GETリクエストのURIの中で指定します。従って、パラメータをURIでどのように表現するか(URIのテンプレート)を定義する必要があります。これはコントラクトと同様に属性として、ソースコード中に付加します。

 次のように、公開するメソッドにWebGet属性を追加し、UriTemplateプロパティに引数名を{}に含める形でURIを記述します。

WebGet属性の追加
[OperationContract]
[WebGet(UriTemplate = "Hello?name={name}")]
string GetMessage(string name);

[OperationContract]
[WebGet(UriTemplate = "GetAddressBook/{id}")]
AddressBookEntry GetAddressBookEntry(string id);

 WebGet属性のUriTemplateプロパティで指定したURIは、そのサービスのAddressの後に付加されます。

 従って、今回のAddressは

http://localhost/WcfTest/Service1.svc

 ですので、その後にURIテンプレートを付加した

http://localhost/WcfTest/Service1.svc/Hello?name=doi

 というアクセスは

IService1.GetMessage("doi")

 という形式でメソッドを呼ぶことに対応します。

 同様に

http://localhost/WcfTest/Service1.svc/GetAddressBookEntry/1

 というアクセスは

IService1.GetAddressBookEntry("1")

 という形式でメソッドを呼ぶことに対応します。

 URIテンプレートにおいて、パスなどは自由に使用することができますので、それぞれの処理に意味のあるURIを割り当てることができます。今回は引数をクエリストリングやパスとして表現しました。

サンプル実行

 では、再度IISへの発行を行い、実行してみましょう。

http://localhost/WcfTest/Service1.svc/Hello?name=doi
GetMessageの呼び出し結果
GetMessageの呼び出し結果
http://localhost/WcfTest/Service1.svc/GetAddressBookEntry/1
GetAddressBookEntryの呼び出し結果
GetAddressBookEntryの呼び出し結果

 それぞれの結果が、直接XMLで表示されていることに注目してください。型名がルート要素となり、それ以下にフィールドが並んでいます。

 こうしたシンプルなXMLであれば、クライアントでのパースも楽に行うことができるでしょう。

 SOAPベースのWebサービスからRESTスタイルのWebサービスに書き換えるまで、ほんのわずかな手順しか掛からなかったことに注目してください。HTTP GETのURIテンプレートを記述する、という少しの手間以外は、ABCを書き換えるだけで切り替えを行うことができました。

サンプル3:JSONサポート

 では、さらに対応形式を変えてみましょう。Ajaxで頻繁に使用されるJSON形式です。JSONはWebブラウザ上のJavaScriptで、文字列としてパースする必要がなく、直接扱うことのできるテキストベースのデータエンコード形式です。前述の通り、.NET Framework 3.5から、WCFでもJSONがサポートされるようになりました。

 JSONはRESTスタイルのWebサービスと同様、WCFのWebプログラミングモデルでサポートされており、バインディングは共通のwebHttpBindingを使用します。従って、ABCの変更は不要で、ごくごくわずかな設定の書き換えだけでJSONサポートを行うことができます。

WebGet属性の書き換え

 JSONサポートに必要なのは、WebGet属性のResponseFormatプロパティを指定する、ただそれだけです。

 次のように、「IService1.cs」内のサービス・コントラクトのWebGet属性に、ResponseFormatとしてWebMessageFormat.Jsonを指定します。

WebGet属性の書き換え。ResponseFormatプロパティの追加
[OperationContract]
[WebGet(UriTemplate = "/Hello?name={name}",
 ResponseFormat = WebMessageFormat.Json)]
string GetMessage(string name);

[OperationContract]
[WebGet(UriTemplate = "/GetAddressBook/{id}",
 ResponseFormat = WebMessageFormat.Json)]
AddressBookEntry GetAddressBookEntry(string id);

 以上で書き換えは終了です。

JSONサポート確認

 では、再度IISへの発行を行い、実行してみましょう。

 それぞれ、次のような結果が返ってきます。

http://localhost/WcfTest/Service1.svc/Hello?name=doi
GetMessage(”doi”) 呼び出し結果
"Hello doi!"
http://localhost/WcfTest/Service1.svc/Hello?name=foo
GetMessage(”foo”) 呼び出し結果
"Hello foo!"
http://localhost/WcfTest/Service1.svc/GetAddressBookEntry/1
GetAddressBookEntry(”1”) 呼び出し結果
{"Address":"Tokyo","Id":1,"Name":"Doi"}
http://localhost/WcfTest/Service1.svc/GetAddressBookEntry/2
GetAddressBookEntry(”2”) 呼び出し結果
{"Address":"?","Id":0,"Name":"Anonymous"}

 文字列を返すだけのGetMessageではよく分かりませんが、GetAddressBookEntryの結果を見ると、フィールドと値が:や,で区切られた、JSON形式で正しく出力されていることが分かります。

 切り替え所要時間は数十秒、といったところでしょうか。REST化以上にJSON化は簡単だったことが実感できたかと思います。

ASP.NET AJAXによるWCF連携
 ASP.NET AJAXからWCFのサービスにアクセスする方法については、本連載の第4回でも紹介しています。併せて参照してください(2008年3月中旬 公開予定)。

まとめ

 WCFの概念と、Visual Studio 2008を使ったWebサービスの構築、RESTスタイルのWebサービス・JSONサポートについて、概観することができました。WCFの機能は非常に大きく、1つの記事ですべて説明することはできませんが、ここで基本的な概念を掴むことができましたので、他の通信方式や、さまざまなビヘイビアなどを扱う場合にも、MSDNのドキュメントを参照しながら理解を進めていけるでしょう。

 実のところ、Visual Studio 2005+ExtensionsとVisual Studio 2008のWCFサポートは、特別な機能差はありません。これは、Visual Studio 2005+Extensionsの時点でMicrosoft Service Configuration Editorが組み込まれており、既に実装に十分な機能を提供していたためです。しかし、.NET Framework 3.5でWCFに加えられた機能は非常に強力で、これまでWCFを使うことのなかった、より多くの開発者が、RESTスタイルのWebサービスやJSONサポートなどの機能を使うため、WCFベースのWebサービス実装に取り組むことになります。そうした際に、.NET Framework 3.5とWCFを標準サポートしたVisual Studio 2008は、心強い味方となってくれることでしょう。

 .NET Framework 3.0のWCFでは、通信方式を簡単に切り替えられる、共存できると言っても、現実的なユースケースが正直想像しづらかったのですが、.NET Framework 3.5のWCFでは、SOAPベースのWebサービス・RESTスタイルのWebサービス・JSON形式などを混在させながら同時に提供するなど、WCFがもともと持っていたポテンシャルを存分に発揮できるようになりました。今後さらに新しいデータの表現形式が出てきたとしても、WCFベースのサービスを構築しておけば、WCFでサポートされた時点ですぐに対応できます。あるいは新しいバインディングを開発すれば、WCFのバージョンアップを待つことなく、新しい形式に対応することもできます。Visual Studio 2008で正式にサポートされた強力な通信フレームワークであるWCFに、この機会にぜひ取り組んでみてください。

 次回は、.NET Framework 3.0から導入されたワークフローフレームワークであるWFについて、Visual Studio 2008でどのように利用できるかを特集します。

参考資料

 
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

  • WINGSプロジェクト 土井 毅(ドイ ツヨシ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5