SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Vista時代のプログラミングモデル .NET Framework 3.0入門

WCF(Windows Communication Foundation)チュートリアル 前編

Vista時代のプログラミングモデル .NET Framework 3.0入門 (3)


  • X ポスト
  • このエントリーをはてなブックマークに追加

WCFはMicrosoftが.NET Framework 3.0から導入した、クライアントと通信を行う際の新しいフレームワークです。さまざまなプロトコルをサポートするWCFは、何よりも「ABC」の理解が重要です。

  • X ポスト
  • このエントリーをはてなブックマークに追加

対象読者

 本記事はC#でのプログラミングを行ったことがある方を対象としています。サンプルを動作させるための環境設定等は「WPF(Windows Presentation Foundation)+XAML入門 前編」ご覧ください。

関連記事

WCF登場の歴史的経緯

 WCF(コードネーム:Indigo)は、.NET Framework 3.0の通信部分を司るコンポーネントです。さて、WCFについて考える前に、これまで存在したネットワーク分散サービスのフレームワークをいくつか列挙してみましょう。

WCF以前のネットワーク分散サービスフレームワーク
フレームワーク 概要
ASP.NET Web Services (ASMX) ASP.NETを使用したXML Web Serviceのフレームワーク
Web Service Enhancements (WSE) 拡張 Webサービス拡張仕様(WS-*)をサポートするフレームワーク
Microsoft メッセージ キュー (MSMQ) Microsoft Message Queuingを使用するフレームワーク
.NET Remoting .NETコンポーネント間で使用可能な通信方式

 WCFが登場したのは、これらのフレームワークに不足があり、完全に新しい通信方式が必要になったため、というわけではありません。しかしこれらのフレームワークは、基本的にそれ単体で使用することが想定された排他的なものであり、複数の通信方式の混在している等の理由から、他のフレームワークへの移行が難しいという問題がありました。

 例えば、ASMXを使用していたアプリケーションを、パフォーマンス向上のために.NET Remotingを使用するものに変更しようとする場合、それらのフレームワークには互換性がないため、多くのコードの書き換えが必要となりました。従って通信テクノロジとして、どのフレームワークを使用するかという決定はプロジェクトの初期で行い、以後は他のフレームワークへの移行を考慮せず、特定のフレームワーク専用のコーディングを行うのが普通でした。

 WCFを使えば、こうしたフレームワーク選択にかかわる問題が無くなり、いずれの通信方式を用いるにしても共通のアプローチで実装を進めることができます。

WCFで使用可能な通信方式

 WCFでは、以下の通信方式を使用することができます。

WCFで使用可能な通信方式
通信方式 概要 相互運用性
TCP TCP/IPを使用する通信方式 WCFコンポーネント
HTTP Webサービスに準拠した通信方式。Basic-ProfileないしはWebサービス拡張仕様をサポートする Webサービスをサポートするアプリケーション
名前付きパイプ 名前付きパイプを使用する通信方式 同一マシン場のWCFコンポーネント
MSMQ Microsoft Message Queuingを使用する通信方式 WCFコンポーネント/MSMQをサポートするアプリケーション
Peer to Peer Windows Peer-to-Peer Networkingを使用する通信方式 WCFコンポーネント

 他にも独自の通信方式を自分で定義し、WCFに組み込むことも可能です。今回のサンプルではHTTPおよびTCPを使用し、ほぼ同一のコードでどのように通信方式を切り替えることができるかを確認します。

キーワードは「ABC」

 WCFの重要な概念となるのが「ABC」です。これは3つのキーワードの頭文字から来ています。

WCFのキーワード「ABC」
頭文字 キーワード 意味
A Address サービスを提供する場所
B Binding サービスで使用するバインディング
C Contract サービスの内容

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

「A」:Address(アドレス)

 アドレスは「サービスをどの場所で提供するか」を定義するもので、URI形式で表現します。その中に含める要素は

  • 使用するトランスポートプロトコル
  • 使用するホスト名
  • (必要な場合)ポート番号
  • 提供するパス

 です。以下にいくつかの例を示します。

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

 通常はポート番号を指定しますが、名前付きパイプとMSMQではポート番号の指定は不要です。

「B」:Binding(バインディング)

 バインディングは「サービスをどのような形でネットワークに公開するか」を定義するものです。

 例えば、通信方式としてHTTPを使用する場合でも、Basic-Profileに準拠する場合とWebサービス拡張仕様に準拠する場合では異なるバインディングを使用します。

 以下に標準でサポートされているバインディングのいくつかを示します。

WCF標準のバインディング
バインディング名 概要
NetTcpBinding TCP/IPを使用するバインディング
BasicHttpBinding WebサービスのBasic-Profileを使用するバインディング
WsHttpBinding Webサービス拡張仕様を使用するバインディング
NetNamedPipeBinding 名前付きパイプを使用するバインディング
NetMsmqBinding MSMQを使用してWCFコンポーネントと接続するためのバインディング
MsmqIntegrationBinding MSMQを使用し、WCFコンポーネントでないMSMQアプリケーションと接続するためのバインディング

 以下に各バインディングの特徴をふまえ、選択の指針を示します。

  • Webサービスとして公開する必要がある場合はHTTP系のバインディングを選択し、必要な相互運用レベルに合わせてBasicHttpBindingあるいはWsHttpBindingを選択しましょう。これらのバインディングはすべてテキストベースでの通信が行われ、WCF以外のフレームワークとも通信が可能です。
  • WCFサービス以外との通信が必要ない場合は、NetTcpBinding、NetNamedPipeBindingなどのバイナリベースでの通信を検討できます。同一マシン間であればNetNamedPipeBindingが高速で、それ以外の場合はNetTcpBindingを使用します。
  • メッセージ・キューの細かな制御が必要な場合はMSMQを使用するバインディングを検討してください。

 前編では1番シンプルなBasicHttpBindingで動作を確認し、後編にてNetTcpBindingへと切り替えてみます。

「C」:Contract(コントラクト)

 コントラクトは「どんなサービスが提供されるか」を定義するものです。WCFのコントラクトは、サービスを提供するクラス・インターフェイスの定義であるサービス・コントラクトと、やり取りするメッセージについての定義をするコントラクトで構成されています。メッセージについてのコントラクトにはいくつか種類があります。

メッセージについてのコントラクトの種類
コントラクト 概要
プリミティブ型 数値・文字列などの.NETの基本データ型は特定の属性を付加することなく、そのまま使用可能
Messageクラス メッセージについての詳細を定義せず、汎用のMessageクラスを使用する方法
データ・コントラクト クラス・インターフェイスのメソッド・プロパティについて属性を付加することでやり取りするデータを指定する方法
メッセージ・コントラクト WCFを介してやり取りするSOAPメッセージの構造を直接定義する方法

 今回は、自作のデータクラスにデータ・コントラクトを定義して使用します。

 最初にサービス・コントラクトを定義しましょう。例えば、WCFサービスを使って会員情報を他のアプリケーションに提供する場合に、次のようなメソッドをサービスとして公開するとします。

  • 会員情報を追加するサービス
  • 会員IDから会員情報を取得するサービス

 これらは.NETのインターフェイスとして次のように定義されます。

サービス・コントラクトを表すC#のインターフェイス
[ServiceContract()]
public interface ISampleService
{
    [OperationContract]
    void addMember(Member member);

    [OperationContract]
    Member getMember(int memberId);
}

 まず、サービスを提供するクラスであるISampleServiceインターフェイスにServiceContract属性が、そして会員情報を追加するaddMemberメソッドおよび取得するgetMemberメソッドそれぞれにOperationContract属性が付加されています。これらはSystem.ServiceModel名前空間で定義されている属性で、サービスをネットワーク上に公開することを表します。

 それぞれの属性の代表的なプロパティを記します。

ServiceContract属性で使用可能なプロパティ
プロパティ名 概要
ConfigurationName WCFサービスの構成名。デフォルトではクラス/インターフェイス名が使用される
Name WCFサービスのメタデータをWSDLとして公開する場合のportType要素のname属性
NameSpace WCFサービスのメタデータをWSDLとして公開する場合のportType要素の名前空間
SessionMode 複数のEndpoint間でのセッションを使用するかどうか
OperationContract属性で使用可能なプロパティ
プロパティ名 概要
Action メソッドを公開する名前。デフォルトではメソッド名がそのまま使用される
IsOneWay メソッドが値を返さないか。このプロパティがtrueのメソッドを呼び出した場合、クライアントはメソッドを呼び出した時点で、メソッドの処理完了を待たずに次の処理に移行する
IsInitiating メソッド呼び出しによってセッションが開始するかどうか。このプロパティがfalseのメソッドの呼び出しは、このプロパティがtrueのメソッドを呼び出した後(=セッションが開始した後)でなければ呼び出すことができない
IsTerminating メソッド呼び出しによってセッションが終了するかどうか

 続いて、メッセージについてのコントラクトを定義します。このサービスで使用するデータである会員情報についてのコントラクトを見てみましょう。

メッセージ・コントラクトを表すC#のインターフェイス
[DataContract]
public class Member
{
    int _id;
    string _name;

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

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

 ここでは、会員情報を表すMemberクラスにDataContract属性が、そして会員IDを表すIdプロパティおよび会員名を表すNameプロパティにDataMember属性が付加されています。これらの属性はSystem.Runtime.Serialization名前空間で定義されており、ネットワークにシリアライズされる、つまりデータがネットワーク上を通過可能することを表します。

 WCFサービスを提供する側とWCFサービスを使用する側では、これらのコントラクトを共有することで、相互に通信を行うことができます。

属性の付加対象
 今回はサービス・コントラクトではインターフェイスに対して、データ・コントラクトでは実際のクラスに対して属性を付加しました。コントラクトを定義するための属性はインターフェイス・クラスのどちらにでも付加することができます。
ただ、サービス実装クラスをクライアントが持つ必要はなく、コントラクトはサービス提供側とクライアント側双方で共有する情報であることからすれば、通常はインターフェイスに対して属性を付加するのが望ましいでしょう。

「ABC」のまとめ

 WCFの「ABC」は、「どこで(Address)・どのように(Binding)・何を(Contract)」提供するかを定義しています。サービス提供側とクライアント側双方で同じ「ABC」を使用することで、齟齬のない通信を行うことができます。これらの「ABC」をまとめてEndpointと呼びます。サービスを提供/使用するためのソケットのようなイメージです。

 WCFサービスは複数のEndpointを持つことができます。つまり、1つのWCFサービス中に、複数の通信方式を持つEndpointを持たせることができるわけです。これもWCFの特徴と言えます。

WCFのEndpointと「ABC」
WCFのEndpointと「ABC」

 さて、Endpointを構成する「ABC」のうち、アドレスとバインディングは使用する通信方式に依存していますが、コントラクトは通信方式に依存していません。

 従って、使用する通信方式を切り替える場合には、サービス提供側とクライアント側双方でアドレスとバインディングを切り替える、つまり別のEndpointを使用すれば、同じコントラクトを使って通信を行うことができます。

実装における「ABC」

 では早速実装に……入る前に、もう少し確認しておきましょう。

 「ABC」のうち、C(コントラクト)は.NETのクラス・インターフェイスに付加された属性で定義することは既に確認しました。では、A(アドレス)とB(バインディング)はどのように定義するのでしょうか。

 WCFではソースコードによる「ABC」指定とXMLによる「ABC」指定の両方を使用することができます。今回はXML形式の設定ファイルでの指定方法を示します。

XMLによる「ABC」定義
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="WCFMemberServiceLibrary.SampleService">
        <endpoint address="http://localhost:8080/MemberService" 
binding="basicHttpBinding"
contract="WCFMemberServiceLibrary.ISampleService"
listenUriMode="Explicit">
</endpoint> </service> </services> </system.serviceModel> </configuration>

 XMLによる「ABC」定義は、.NET標準の構成ファイル(Windowsアプリケーションでは「app.config」、Webアプリケーションの場合は「web.config」)を使用します。そして、endpoint要素のaddressbindingcontractという3属性で「ABC」を定義します。

 address属性はサービスを提供するURIを、binding属性は使用するバインディングを、contract属性はサービス・コントラクトを定義したクラス・インターフェイスを、それぞれ指定します。

endpoint要素のlistenUriMode属性
 listenUriMode属性は公開するアドレスを明示的に指定するか、一意になるように自動生成するかを指定する属性です。デフォルトの値であるExplicitではaddress属性の値がそのまま使用されます。
値としてUniqueを設定すると、アドレスの末尾にこのサービスについての一意な値であるGUIDが付加され、アドレスの衝突を避けてくれます。また、NetTcpBindingの場合は未使用のポート番号も自動的に選択してくれます。

 ただ、このXMLを手動で編集するのは煩雑であるため、Visual Studio 2005 extensions for WCFで「Microsoft Service Configuration Editor」というソフトウェアが提供されており、GUIでこれらの定義を編集することができます。詳しくは後述します。

クライアント側の「ABC」実装

 もう1つだけ確認事項です。サービス提供側で定義した「ABC」ですが、クライアント側ではどのように共有すればよいのでしょうか。

 まず、サービス提供側の構成ファイル(app.config、web.config)をクライアント側のMicrosoft Service Configuration Editorで読み込んで必要な情報を生成する、という方法があります。この場合、app.configの生成と同時に、サービス提供側で作成したコントラクトのソースコードをクライアント側にコピーして共有する必要があります。

 もう1つは、通信方式としてWebサービスを使用する場合は、Webサービスを介してコントラクトについてのメタデータを取得することで、「ABC」を共有することができます。今回は両方の方式をサンプルとして示します。

次のページ
WCFを使ったサンプルの実装 1

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Vista時代のプログラミングモデル .NET Framework 3.0入門連載記事一覧

もっと読む

この記事の著者

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

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

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

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

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1157 2008/08/19 17:24

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング