■1-4. サービス・ホストの実装(セルフ・ホストの実装)
先に見てきたようにWCFのサービスをホストさせるプロセスとしては、IIS上のASP.NETワーカー・プロセスにホストさせるといった従来のASP.NETでのWebサービスのようなホスティングが可能だ。しかし、コンソール・アプリケーションやNTサービスなど、ホストさせるプロセスを自分でコーディングするといった方法も取れる。こういった場合を「セルフ・ホスト」と呼び、IISにホストさせる場合と明確に分けている。
下記のコードは、セルフ・ホストのコーディング例であり、コンソール・アプリケーションでWCFのホストを実装した場合の簡単なサンプルである。
public class ServiceHosting
{
// コンソール・アプリであるこの.EXE内でサービスをホスト
public static void Main()
{
try
{
Uri baseAddress =
new Uri("http://localhost:8080/WinFxService");
// ベース・アドレスを提供し、ServiceHostをインスタンス化
using (ServiceHost serviceHost
= new ServiceHost(typeof(MyService), baseAddress))
{
// ServiceHostをOpenし、メッセージのリスニングを開始
serviceHost.Open();
Console.WriteLine("リスナーのURIを表示:");
foreach (ChannelDispatcher channeldispatcher
in serviceHost.ChannelDispatchers)
{
Console.WriteLine("\t{0}",
channeldispatcher.Listener.Uri.ToString());
}
Console.WriteLine("サービス実行中");
Console.WriteLine("ENTERキーでサービス終了");
Console.ReadLine();
// ServiceHostをCloseし、サービスをシャットダウン
serviceHost.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
ちなみにここでは、先ほどのIISホスト時のコンフィグレーション・ファイルの「Web.config」を「App.config」にリネームし、内容は変更せず使用している。つまり、A/B/Cの定義はコンフィグレーションから提供される形態である。
また、セルフ・ホストの場合、IISホスト時に必要だった「Service.svc」ファイル自体は必要はない。
参考までにコンフィグレーションを使用せずにプログラム・コードのみで設定してみた例を下記に掲載する。
// アドレス(Address)の設定
Uri address =
new Uri("http://localhost:8080/WinFxService");
// バインディング(Binding)の設定
WSHttpBinding binding = new WSHttpBinding();
// コントラクト(Contract)の設定
Type contract = typeof(IMyService);
// ServiceHostのインスタンス化
ServiceHost serviceHost = new ServiceHost(typeof(MyService));
// ServiceHostにABCを指定
serviceHost.AddServiceEndpoint(contract, binding, address);
// ServiceHostをOpenし、メッセージのリスニングを開始
serviceHost.Open();
コンフィグレーションでもコードでも設定は可能であるが、コンフィグレーションの方が細かな調整をコードの外から行うことが可能であり柔軟性と保守性の向上が図れるため、基本的にコンフィグレーションの方が望ましいといえる。
【コラム】コンフィグレーションかコードか
WCFのサービス設定やクライアント・サイドの各種設定をコンフィグレーションで行うのかコードで行うのかに関しては大きく下記のような考え方を取るとよいだろう。
基本的には配置の柔軟性と保守性の向上を図るため、企業内で使用するアプリケーションにおいてはコンフィグレーションによる設定が望ましいといえる。
さて、これからはサービスを利用するクライアント・サイドの実装方法に関して具体的に見ていこう。
クライアント・サイドの実装アプローチとしては、WCFサービスを参照することでプロキシやコンフィグレーションを自動生成させるといった開発環境の機能を有効利用する方法と、プロキシの自動生成は利用せずすべてフルスクラッチでハンドメイドするといった方法が取り得る。自動生成は便利であり開発生産性も向上するが、コンフィグレーションを完全かつ明示的にコントロールしたい場合は後者の方が有効だ。
ここでは、まず自動生成を利用せずに記述した場合を掲載し、その後で自動生成の手順を掲載する。すべてハンドメイドする場合の具体的な手順は以下のとおりとなる。
■2-1-1. サービス・インターフェイスの定義
すべてハンドメイドする場合はサービス・サイドで使用したサービス・コントラクト、オペレーション・コントラクト、データ・コントラクト(あるいはメッセージ・コントラクトなど)の定義をそのままクライアント・サイドでも使用することになる。
当然ながらサービス・サイドのWSDLしか入手できない場合はこの手法は取れないので、ツールによるプロキシやコンフィグレーションの自動生成といった方法を取ることになる。
さて、まずクライアント・アプリケーションを作成しよう。ここでは手っ取り早くWindowsフォームのアプリケーションを作成する。プロジェクトの新規作成でWindowsアプリケーションを作成する(本稿の例ではプロジェクト名として「WindowsClient」を指定)。そして、サービス・サイドのコントラクトのファイルをそのままこのプロジェクトにコピーする。なお、これに伴い、System.ServiceModelアセンブリおよびSystem.Runtime.Serializationアセンブリへの参照設定が必要となるので設定しておく。
■2-1-2. クライアント・サイドのサービス利用コードの実装
次にクライアント・サイドでサービスを利用するコードを記述する。ここでは、UI(ユーザー・インターフェイス)の作成を効率化するためにオブジェクト・データ・バインディングを利用してみよう。
いったん、現段階でプロジェクトをビルドし、クラスをリフレクション可能な状況にしておく。そして、[新しいデータソースの追加]を選択し、データソースとして「オブジェクト」を選択する。
そして、サービスと交換するデータ・コントラクトのクラスであるProductクラスを選択する。
この設定のままデータソースを作成すると、次の画面のようなデータソースが新規に追加される。
その後、データソース(上図の「Product」の部分)をフォームにドラッグ&ドロップする。
なお、フォームに自動的に追加されるBindingNavigatorコントロールは不要なため削除しておき、フォーム上に新たに[読み込み]ボタンを配置する。そのボタンのClickイベント・ハンドラに下記のコードを記述する。
private void button1_Click(object sender, EventArgs e)
{
// ChannelFactoryを使用したサービス呼び出し
ChannelFactory<IMyService> fact
= new ChannelFactory<IMyService>("Endpoint1");
IMyService proxy = fact.CreateChannel();
Product product = proxy.GetData();
productBindingSource.DataSource = product;
((IClientChannel)proxy).Close();
}
また、ChannelFactoryなどのSystem.ServiceModel名前空間のクラスの使用するため下記usingディレクティブも追加しておく。
using System.ServiceModel;
このコードによっていったん、サービス・コントラクトを型パラメータとしてチャネル・ファクトリ(ChannelFactory)を生成する。その際、コンフィグレーション・ファイル中の、“Endpoint1”という名前のエンドポイント情報を参照する。
その後、チャネル・ファクトリ経由でサービスとの通信路であるチャネルを生成する。あとはそのチャネル自体がサービスのプロキシとしての役目を担うため、プロキシ経由でサービス・サイドのメソッドを起動するといった流れになる。
処理が終了すればチャネルはクローズしておく。プロキシを開発環境からサービス参照によって自動生成しない場合はおおむねこのようなコードを書くことになる。
Copyright© Digital Advantage Corp. All Rights Reserved.