例えば、先ほどのクラスのメソッドをサービスとして実装するには、WCFでは以下のようになる。
// サービス・コントラクトの定義
[ServiceContract]
public interface IMyService
{
[OperationContract]
string MyOperation1(string myValue1);
}
// サービス・コントラクトを実装するサービス・クラス
public class MyService : IMyService
{
public string MyOperation1(string myValue1)
{
return "Hello: " + myValue1;
}
}
このコードは先ほどの単なるクラスのメソッドを、サービスのメソッドに変更している。これには、まず外部に公開するサービスのインターフェイスをコントラクトとして定義する。ここではIMyServiceインターフェイスがこのサービスのコントラクトに当たり、このインターフェイスにServiceContract属性および、公開するメソッドにOperationContract属性を付与する。
後はこのインターフェイスを実装するクラス(いわばサービス自体の実装クラス)を作ればよい。これにより単なるクラスでしかなかったものが、WCFのサービスとして変身することになる。
次のコードは上記のサービスを利用するクライアント・サイドのコードになる。
localhost.MyServiceProxy proxy = new localhost.MyServiceProxy();
string str = proxy.MyOperation1(textBox1.Text);
proxy.Close();
WCFで実装したサービスを利用するには、クライアントとサービス間で共有すべきコントラクトを定義した後、従来のプログラミング・モデルにおけるWebサービスの呼び出しと同じように、クライアント・サイドのプロキシをインスタンス化して、サービスの提供するメソッドを使用すればよい。最も簡単な例だが、これが基本的なWCFでのプログラミング・スタイルとなる。
なお、このアプリケーションの使用するプロトコルは、コンフィグレーションによって外部から臨機応変に変更可能である。
デフォルトですでにメッセージは署名暗号化されるし、メッセージの安全な伝送(順序制御、重複受信の排除、欠落時の再送要求)も行われる。また使用できるプロトコルは、名前付きパイプ(Named Pipe)、TCP、HTTP、MSMQと選択肢の幅も広く、エンコーディングに関してもネイティブのバイナリ(Binary Serialization)や、MTOM(SOAP Message Transmission Optimization Mechanism:バイナリ・データを含むSOAPメッセージ)、Text/XML(テキスト形式XML)などと用途に応じて柔軟に変更可能だ。
つまり、基本的な実装コードの構造は同じ(=ServiceContract属性やOperationContract属性を付加するだけ)にもかかわらず、分散アプリケーションが持つさまざまな要件に応じて下位の転送プロトコル、エンコーダ、適用するWS-*仕様を柔軟に差し替えられるのである。
■WCFのコンフィグレーション・ベースによる設定
例えば、先ほど示したサービスに対するコンフィグレーションは下記のようになっている。
<?xml version="1.0" encoding="utf-8" ?>
<configuration
xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<!--サービス・サイドのコンフィグレーション-->
<system.serviceModel>
<services>
<service name="Microsoft.ServiceModel.Samples.MyService">
<!-- サービスのEndpoint定義-->
<endpoint
address=""
binding="basicHttpBinding"
contract="Microsoft.ServiceModel.Samples.IMyService" />
</service>
</services>
</system.serviceModel>
</configuration>
このコンフィグレーションでは、プロトコルにHTTPを使用し、メッセージ・エンコーディングにはText/XMLを使用した、WS-I Basic Profile準拠の相互運用性が高いサービスの構成例である。
この場合のメッセージは、パケットモニタで以下のように確認できる。
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<MyOperation1 xmlns="http://tempuri.org/">
<myValue1>伊藤</myValue1>
</MyOperation1>
</s:Body>
</s:Envelope
非常に単純なSOAPメッセージとなっており、もちろんメッセージの秘匿性、完全性は保証されておらず、内容も平文で確認することが可能な状況である。
さて、ここでメッセージ・セキュリティを確保したくなった場合、どうすればよいか。最もシンプルな方法は、WS-SecurityなどのWebサービスの拡張仕様を適用するようにコンフィグレーションを変えることである。
下記は実際にWS-Securityを適用するように変更した後のコンフィグレーションである。
<?xml version="1.0" encoding="utf-8" ?>
<configuration
xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<!--サービス・サイドの・コンフィグレーション-->
<system.serviceModel>
<services>
<service name="Microsoft.ServiceModel.Samples.MyService">
<!-- サービスのEndpoint定義-->
<endpoint
address=""
binding="wsHttpBinding"
contract="Microsoft.ServiceModel.Samples.IMyService"/>
</service>
</services>
</system.serviceModel>
</configuration>
この場合のメッセージはパケットモニタで以下のように確認できる。
<s:Envelope
xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
……中略……
<s:Header>
……中略……
</s:Header>
<s:Body u:Id="_2">
……中略……
<e:EncryptedDataId="_3"
Type="http://www.w3.org/2001/04/xmlenc#Content"
xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
……中略……
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
……中略……
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:Reference URI="#_1" />
</o:SecurityTokenReference>
</KeyInfo>
……中略……
<e:CipherData>
<e:CipherValue>HMbw5+O0jgqk+kHhKwasdsKo0T2bhD/4mY3CB2/l17tAD…
</e:CipherValue>
</e:CipherData>
</e:EncryptedData>
</s:Body>
</s:Envelope>
上記はメッセージの一部を掲載したものであるが、先ほどのWS-I Basic Profile準拠のシンプルなSOAPメッセージとは異なり、メッセージ本体が暗号化されメッセージ・セキュリティが確保されていることが分かる。コンフィグレーションは、<endpoint>要素のbinding属性の値を「basicHttpBinding」から「wsHttpBinding」に変更しただけである。
もしここで転送パフォーマンスを重視した構成に変えたい場合には(例えばイントラネットの信頼ドメイン内にあるアプリケーション・サーバとの間でWCF対向通信を行うような場合)、あえてセキュリティは確保せず、プロトコルもTCPで特定ポートを使用し、エンコーディングにはバイナリ(Binary Serialization)を使用した方が効率的だ。
このようなとき、従来であればASP.NET Webサービスから.NETリモート処理へアプリケーションの通信方式を移行するといった対処となり、それなりの手間が発生したわけである。
これがWCFの場合は、下記のようにコンフィグレーションを変更するだけで対処ができ、大幅に手間が軽減される。
<?xml version="1.0" encoding="utf-8" ?>
<configuration
xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<!-- サービス・サイドのコンフィグレーション-->
<system.serviceModel>
<services>
<service type="Microsoft.ServiceModel.Samples.MyService">
<!-- サービスのEndpoint定義-->
<endpoint
address=""
binding="netTcpBinding"
bindingConfiguration="Binding1"
contract="Microsoft.ServiceModel.Samples.IMyService"/>
</service>
</services>
<!-- サービスのBinding定義-->
<bindings>
<!-- netTcpBinding用 -->
<netTcpBinding>
<binding name="Binding1">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
このように1つのプログラミング・モデルに基づきサービスを実装することになるので、状況に応じた変更が非常に容易なものとなっているわけだ。このようなプログラミングに関するより詳細な解説は、次回以降に行う予定だ*3。ここではそのWCFの持つプログラミング上のメリットを理解していただきたい。
*3 上記の例のようにコンフィグレーションを状況に応じて書き換えるといった手法もあるが、さまざまな状況に対応可能なエンドポイントを並列に用意しておくといった手法も取れる。詳細は次回以降で解説する。
次にWCFのWinFXにおける位置付けについて説明しよう。
Copyright© Digital Advantage Corp. All Rights Reserved.