Part 2. Hello World WCF サーバの開発
では、前回のエントリに引き続いて、今回は Hello World メッセージを返す WCF サーバの開発を行ってみたいと思います。WCF のランタイムはポータブル(いろんな場所に持っていける)に設計されているのが面白いところで、IIS 上はもちろんのこと、コンソールアプリケーションや Windows サービスなどにも簡単にホストすることができるように設計されています。が、いきなりそれらの話をするも大変なので、まずはコンソールアプリケーションを使って、SOAP over HTTP のリクエストを受け付ける Hello World WCF サーバを開発する、という作業を行ってみたいと思います。
・WCF サービスの作成
・WCF ホストプロセスの作成
・構成設定ファイルの作成
・サービスビヘイビアによる MEX (Metadata Exchange) の作成
・WCF テストツールによる WCF サーバの動作確認
なお、本サンプルでは Visual Studio 2008 に用意されている WCF ライブラリのプロジェクトテンプレートなどは一切使いません。これは以下の理由によります。
- テンプレートやウィザードを使ってしまうと何をやってるのかわからくなる。
- Application Architecture for .NET などの考え方に基づいて、通信インタフェース(SI)を分離するという設計モデルを取る場合、SI 内部でさらにインタフェースを分離することにはあまり意味がない。
簡単にいえば、WCF ライブラリのプロジェクトテンプレートは、従来の考え方(ビジネスロジックが直接通信機能を持つ)に近い設計モデルに基づいて作られているものだと思います(と自分は解釈している)。なので、ここではあえてプロジェクトテンプレートは利用せずに、WCF サーバを作ってみたいと思います。
※ 以下の作業を Windows Vista や Windows 2008 で行う場合には、Visual Studio 2008 を管理者特権で動作させるようにしてください。VS2008 を管理者特権で動作させるためには、以下の 2 つのファイルのプロパティとして、管理者で動作させる設定を付与してください。
- C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe
- C:\Program Files (x86)\Common Files\microsoft shared\MSEnv\VSLauncher.exe
[Step. 4] WCF サービスの作成
まず、Visual Studio 2008 のコンソールアプリケーションプロジェクトを使って、WCF サーバとなるアプリケーションを作成します。ここでは、名前を "Sample01.Server" としておきましょう。
作成されたプロジェクトに対して、以下の作業を行います。
- System.ServiceModel.dll ファイルに参照設定をかける。
- WcfService.cs クラスファイルを追加し、WCF サービスのコードを記述する。(System.ServiceModel 名前空間に対する using 設定も忘れずに。)
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.ServiceModel;
6:
7: namespace Sample01.Server
8: {
9: [ServiceContract]
10: public class WcfService
11: {
12: [OperationContract]
13: public string GetMessage(string name)
14: {
15: return "Hello World, " + name;
16: }
17: }
18: }
[Step. 5] WCF ホストプロセスの作成
以上で WCF サービスの作成(実際に処理を行うクラス)は終わりですが、このサービスを動作させるためには、サービスをホストするためのプロセス(ホストプロセス)が必要になります。このため、コンソールアプリケーションの Program.cs ファイルの Main() 関数に、WCF ランタイム起動のためのコードを記述します。
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.ServiceModel;
6:
7: namespace Sample01.Server
8: {
9: class Program
10: {
11: static void Main(string[] args)
12: {
13: using (ServiceHost host = new ServiceHost(typeof(WcfService)))
14: {
15: host.Open();
16: Console.WriteLine("WCF サーバを起動しました。");
17: Console.ReadLine();
18: host.Close();
19: }
20: }
21: }
22: }
1 つのサービスホストで起動できる WCF サービス(の実装クラス)は 1 つだけです。ですので、もし WCF サービスの実装クラスが複数ある場合には、以下のように記述します。(ここではコードを見やすくするために try-finally を省略してます)
1: ServiceHost host1 = new ServiceHost(typeof(WcfService1));
2: ServiceHost host2 = new ServiceHost(typeof(WcfService2));
3: host1.Open();
4: host2.Open();
5: Console.WriteLine("WCF サーバを起動しました。");
6: Console.ReadLine();
7: host1.Close();
8: host2.Close();
以上で WCF サービスとホストプロセスの作成はおしまいです。ですが、実際に Ctrl + F5 キーでこれを起動してみると、例外が発生して動作しません。これは、サービスホストが WCF パイプライン(エンドポイント、サービス要求を受け付ける受け口)を作成するために必要な構成設定が準備されていないことによるものです。
[Step. 6] 構成設定ファイルの作成
プロジェクトに app.config ファイルを追加し、ここに WCF エンドポイントに関する構成設定を記述します。構成設定ファイルは手で書くこともできますが、かなり大変なのでツールを使うことをお勧めします。以下の手順で作業を行ってください。
- プロジェクトに app.config ファイルを追加する。
- スタートメニュー内の Microsoft Windows SDK v6.0a → Tools 内にある、「サービス構成エディタ」を起動する。
- ファイル → 開く → 構成ファイルを選択し、先ほど追加した app.config ファイル(C:\Users\nakama\Documents\Visual Studio 2008\Projects\Sample01.Server\Sample01.Server\app.config)を開く。
これにより、エンドポイントの構成設定ファイルを、ツールを使って書くことができるようになります。
なお、サービス構成エディタツールを毎回、スタートメニューから開くのは大変です。なので、VS2008 上にツールとして登録してしまうと便利です。具体的には以下のようにします。
- app.config ファイルを右クリックし、「ファイルを開くアプリケーションの選択」を選ぶ。
- ここに SvcConfigEditor.exe をプログラムとして追加して使う。
※ サービス構成エディタは OS や Visual Studio のバージョンによって、インストール先が異なる場合がありますので注意してください。VS2008 の場合には C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SvcConfigEditor.exe にあります。
ここに、エンドポイントの構成設定情報を書いていきます。一応、ウィザードもあるのですが、ここでは敢えてまず手で指定していってみます。
- 左側の「構成」ペイン内の「サービス」フォルダを右クリックし、新しいサービスを追加。
- サービスの名前として、"Sample01.Server.WcfService" (WCF サービス実装クラスのフルネーム)を指定。
- その下側にある「エンドポイント」フォルダから、「新しいサービスエンドポイント」を指定して、エンドポイントを追加する。
- このエンドポイントに、Adress, Binding, Contract の 3 つを指定する。(後述)
エンドポイントに指定しなければならない要素は、A/B/C の 3 つです。指定に関しては、以下の点に気をつけてください。
A (Address) について
B (Binding) について
- いろんな種類の Binding が利用できますが、今回は単純な SOAP over HTTP を使うので、basicHttpBinding を使ってください。
- その他の Binding については、Part.1 に簡単に紹介してありますのでそちらをご参照を。Part. 3 でも多少紹介します。
C (Contract) について
- [ServiceContract] を付与した I/F を、フルネームで指定します。
- 今回のサンプルのように、サービス実装クラスに直接 [ServiceContract] 属性を付与している場合には、サービス実装クラスの名前を指定してください。インタフェースを分離して定義している場合には、そちらを指定します。
- なお、Contract を指定しなければならないのは、WCF サービス実装クラスが複数の I/F を持っているケースを想定しています。(通常、ひとつの WCF サービス実装クラスが持つ外部公開 I/F は 1 つですが、インタフェースを分離して定義した場合には、ひとつの WCF サービス実装クラスが複数の [ServiceContract] 属性つきインタフェースを継承している場合があります。)
以上が終了したら、ファイルをセーブし、Visual Studio に戻ります。ツールから app.config ファイルが書き出され、今、記述した構成設定が画面上に現われます。
1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <system.serviceModel>
4: <services>
5: <service name="Sample01.Server.WcfService">
6: <endpoint address="http://localhost:8000/Sample01.Server/WcfService"
7: binding="basicHttpBinding" contract="Sample01.Server.WcfService" />
8: </service>
9: </services>
10: </system.serviceModel>
11: </configuration>
この状況でコンソールアプリケーションを実行すると、今度は問題なく WCF サーバが起動します。
この WCF サーバは、http://localhost:8000/Sample01.Server/WcfService というアドレスに対して HTTP で送信した SOAP メッセージを処理できるようになっています。しかし、ASP.NET XML Web サービス(*.asmx)とは異なり、ブラウザなどでこのアドレスを呼び出すことはできません。呼び出してみると、以下のように HTTP 400 エラー(要求形式がおかしい)が発生します。
※ ASP.NET XML Web サービスにおいて、*.asmx ファイルをブラウザから呼び出すことができたのは、これは *.asmx が、SOAP 形式ではないリクエスト(具体的には HTTP-GET や HTTP-POST と呼ばれる方式のリクエスト)を処理できるように作られていたからです。WCF ではこの挙動が厳格になっており、ここまでの設定だけでは、SOAP 形式以外のリクエストを一切処理することができません。
[Step. 7] サービスビヘイビアによる MEX (MetadataExchange) の作成
また、現在のままではもう一つ困るポイントがあります。それは、クライアント側にプロキシクラスを作成することができない、という点です。クライアント側にプロキシクラスを作成するには、
- サーバ側で WSDL ファイル(サービスの情報を記載した XML ファイル)を公開しておく。
- これをクライアント側に取り込ませて、プロキシクラスを作成する。
という方法がもっとも簡単なのですが、現状のままでは WSDL ファイルが公開されていません。このため、サービスビヘイビアと呼ばれるものを利用して、WSDL ファイルを公開するようにします。
サービスビヘイビアとは、簡単にいえばサーバ(サービスホスト)に追加するプラグイン型のパワーアップモジュールで、このモジュールを追加することで、以下のようなことができるようになります。
- WSDL ファイルの自動作成と公開(serviceMetadata サービスビヘイビア)
- デバッグ用の情報公開(serviceDebug サービスビヘイビア)
- サーバの証明書やユーザのパスワード情報の管理機能(serviceCredentials サービスビヘイビア)
ここでは、serviceMetadata と serviceDebug をサーバに追加して、WCF サーバをパワーアップすることにします。

具体的には以下の作業を行います。
- もし WCF サーバアプリケーション(さっきのコンソールアプリケーション)を動作させているのであればこれを停止する。
- app.config ファイルを SvcConfigEditor.exe で開く。(すでに開いていればそのまま編集)
- 「構成」ペイン → 「詳細設定」 → 「サービス動作」 → 「新しいサービス動作の構成」を選択して、サービスビヘイビア定義を作成。
- まずサービス動作の名前を変更。(NewBehavior → お好きな名前に。ここでは "WcfService_ServiceBehavior" にしました。)
- 次に、「動的要素の拡張の位置」のところから「追加」を選択し、serviceDebug と serviceMetadata を追加する。(訳語がもはや意味不明ですが、要するにサービスビヘイビアについて、拡張モジュールを追加して、それを入れる順番を指定してください、という意味です。正直、こういうものは無理に訳さない方がいい気がする....)
次に、各サービスビヘイビアモジュールのプロパティを設定します。
そして、最後に以下の作業を行います。(この作業を忘れがちなので注意してください。)
- サービスセクションに戻り、BehaviorConfiguration として、先ほど作成したサービスビヘイビア構成設定を割り当てる。

以上で設定作業はおしまいです。ファイルをセーブしてから WCF サーバを立ち上げなおしてみてください。
見た目は何も変わっていませんが、Web ブラウザを起動し、以下の 2 つの URL を呼び出してみてください。
[ヘルプページ]

[WSDL 情報]
[Step. 8] WCF テストツールによる WCF サーバの動作確認
さて、この状態で WCF サーバの動作確認を行いたいところですが、ASP.NET XML Web サービス(*.asmx)の場合と異なり、WCF では簡単にサーバを呼び出すことができません。これは、WCF がマルチプロトコル対応であるために、サーバを呼び出す方法が一定しないことが大きな要因だろうと思います。
(どうせなら、SOAP over HTTP の場合に限っては、*.asmx と同様にヘルプページからテストも行えるようにしてほしいところなのですが、とつぶやいてみる....まあ贅沢を言っちゃいけないのかもですが。)
この問題に対処するため、Visual Studio 2008 では、WSDL 情報を元にして WCF サーバを呼び出す汎用テストクライアントツール WcfTestClient.exe が用意されました。
具体的には以下のようにして利用します。
- まず、WCF サーバを起動しておきます。(※ WCF サーバが起動していないと、WSDL ファイルが入手できないため。)
- C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\WcfTestClient.exe を起動します。
- ファイル → サービスの追加を選択し、エンドポイントアドレスの入力欄に、WSDL ファイルが公開されている URL (ここでは http://localhost:8000/Sample01.Server/WcfService/mex )を指定します。
※ WcfTestClient.exe の起動時のコマンドライン引数として、WSDL ファイルのアドレスを与えても OK です。
以上の作業により、WCF サービスを呼び出す準備ができるので、あとはメソッドを選択し、パラメータ引数を入力して起動ボタンを押下してください。これにより WCF サービスを呼び出すことができます。
なお、このツールは TCP/IP 通信や名前つきパイプ通信でも利用できます。WSDL ファイルさえ入手できれば、あとはそれを元に動的にテストクライアントを組み上げてくれるツールになっているので、適宜活用するとよいでしょう。(…といっても、実際のアプリケーション開発の場合には、さくっとクライアントアプリを作ってしまった方が手っ取り早いのですが。)
[Step. 9] (おまけ) 構成設定ファイルを使わない方法
以上で説明はおしまいですが、最後におまけとして、構成設定ファイルを使わないで WCF サーバを起動する方法について説明しておきます。
実際に自分のアプリケーションで WCF を使おうと思った場合にネックになる大きなポイントの一つに、構成設定データの維持がえらく大変、という点があります。今回のサンプルの場合には、WCF サービスが一つだったので構成設定データを作成するのもラクでしたが、実際の業務アプリケーションでは WCF サービスがたくさん作成されることになるため、構成設定ファイルを作成・メンテするのがとかく面倒になります。こうした場合には、アプリケーションコードでエンドポイントを構成する手段を検討してみてください。
例えば、以下のようなコードを書くと、app.config なしで WCF サービスを起動することができます。
1: using (ServiceHost host = new ServiceHost(typeof(WcfService)))
2: {
3: // ① エンドポイントの手動構成設定 (C/B/A を指定)
4: // バインディングの構成設定を行いたい場合には、Binding インスタンスのプロパティを設定する
5: host.AddServiceEndpoint(typeof(WcfService), new BasicHttpBinding(),
6: "http://localhost:8000/Sample08.Server/WcfService");
7: // ② ビヘイビアの手動構成設定
8: // すでにいくつかのビヘイビアは既定で追加されているため、取り払ってから再設定する
9: host.Description.Behaviors.Remove(typeof(ServiceDebugBehavior));
10: host.Description.Behaviors.Remove(typeof(ServiceMetadataBehavior));
11: host.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
12: host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true,
13: HttpGetUrl = new Uri("http://localhost:8000/Sample08.Server/WcfService/mex") });
14:
15: // ホストのオープン
16: host.Open();
17: Console.WriteLine("WCF サービスを起動しました。");
18: Console.ReadLine();
19: host.Close();
20: }
このコードについては詳細には説明しませんが、このようにコードによって構成設定を行う方法もある、というのを知っておくと何かと便利ですので、覚えておいてください。
[ここまでのまとめ]
今回のエントリのキーポイントをまとめると、以下のようになります。
- [ServiceContract], [OperationContract] 属性を使って、WCF サービスを作成する。
- WCF サービスを動作させるためには、サービスホスト(ServiceHost)の初期化とオープンが必要。
- サービスホストを動作させるためには、構成設定ファイルを使ってエンドポイントの構成を指定しておく必要がある。(アプリケーションコードを使ってエンドポイントの構成を行うことも可能)
- さらに、サービスビヘイビアを追加することで、ヘルプページや WSDL 情報を作成・公開したりすることができる。
引き続き次回の Part.3 では、この WCF サーバに対するクライアントアプリケーションの作成と、通信プロトコルの差し替えなどを行ってみることにしたいと思います。