開発者による Windows Communication Foundation 4 の概要
Aaron Skonnard、Pluralsight
オリジナル: 2009 年 11 月
RTM に更新: 2010 年 4 月
概要
.NET 4 には魅力的な新機能がいくつか付属しており、Windows Communication Foundation (WCF) の領域での改善を歓迎しました。 これらの WCF の機能強化は、主に開発者エクスペリエンスを簡素化し、より多くのコミュニケーション シナリオを可能にし、"ワークフロー サービス" を一流の市民にすることで Windows Workflow Foundation (WF) との豊富な統合を提供することに重点を置いています。
WCF 4 の変更のほとんどは、今日の一般的なシナリオをより簡単にし、新しいコミュニケーション シナリオと開発スタイルを可能にすることに重点を置いています。 その結果、既存の WCF ソリューションを .NET 4 に移行すると、移行の点でかなりシームレスになります。 次に、先に進むソリューションで利用する WCF 4 機能を決定するだけです。 この記事の残りの部分では、新しい WCF 4 の各機能領域について説明し、そのしくみについて説明します。
WCF 4 の新機能
WCF 4 にはさまざまな特定の機能が付属していますが、図 1 では、以下の論文全体で注目するメイン機能領域について説明します。 これらの機能領域は、WCF 4 の新機能の大部分をまとめたものであり、.NET フレームワークのこのリリースで提供されるトップレベルの機会を強調しています。
図 1: WCF 4 の機能領域
機能分野 | 説明 |
---|---|
簡略化された構成 |
既定のエンドポイント、バインド、および動作の構成のサポートによる WCF 構成セクションの簡略化。 これらの変更により、構成不要のサービスをホストできるため、最も一般的な WCF シナリオの開発者エクスペリエンスが大幅に簡素化されます。 |
探索 |
標準のWS-Discovery プロトコルに準拠したアドホックおよびマネージド サービス検出動作の両方に対する新しいフレームワークサポート。 |
ルーティング サービス |
WCF ソリューションで使用できる構成可能なルーティング サービスの新しいフレームワーク サポート。 コンテンツ ベースのルーティング、プロトコル ブリッジング、エラー処理の機能を提供します。 |
REST の機能強化 |
REST サービス開発を簡略化するいくつかの追加機能とツールを備えた WCF WebHttp Services の機能強化。 |
ワークフロー サービス |
WCF と WF を統合して、宣言型の実行時間の長いワークフロー サービスを実装するための豊富なフレームワークサポート。 この新しいプログラミング モデルでは、両方のフレームワークで提供する必要がある最適なフレームワーク (WCF & WF) が提供されます。 |
これらのメイン機能領域のカバーが完了したら、.NET 4 に付属するより高度な下位レベルの WCF 機能について簡単に説明します。これには、型解決機能の向上、競合するコンシューマーとのキューのサポート ("コンテキストの受信")、バイト ストリーム エンコーダーを介したラップされていないバイナリ データのサポート、高パフォーマンスの ETW ベースのトレースのサポートなどが含まれます。
完了すると、WCF 4 が使いやすくなり、今日の最も一般的なシナリオや開発スタイルの一部に対してより組み込みのサポートが提供されることがわかります。
簡略化された構成
WCF が 3.x で提供する統合プログラミング モデルは、祝福と呪いの両方であり、さまざまな通信シナリオのサービス ロジックの記述を簡略化しますが、開始する前に理解する必要があるさまざまな基になる通信オプションが提供されるため、構成側の複雑さが増します。
実際には、WCF の構成は、通常、WCF を実際に使用する最もコストの高い領域になり、その複雑さの多くは、それに対処する準備ができていない IT/運用スタッフにあります。
このような現実を考えると、WCF 3.x を使用する際の複雑さを考慮すると、前身の ASP.NET Web サービス (ASMX) よりも使用が困難であると合理的に結論付けられる場合があります。 ASMX を使用すると、[WebMethod] 操作を定義でき、ランタイムは基になる通信の既定の構成を自動的に提供しました。 一方、WCF 3.x に移行する場合、開発者は、少なくとも 1 つのエンドポイントを定義するためのさまざまな WCF 構成オプションについて十分に理解する必要があります。 また、多くの場合、構成オプションの数が多いと、一部の開発者が怖がることがあります。
WCF の全体的なエクスペリエンスを ASMX と同じように簡単にするために、WCF 4 には、WCF 構成の必要性を完全に排除する新しい "既定の構成" モデルが付属しています。 特定のサービスに対して WCF 構成を指定しない場合、WCF 4 ランタイムは、一部の標準エンドポイントと既定のバインディング/動作構成を使用してサービスを自動的に構成します。 これにより、WCF サービスの稼働が大幅に容易になります。特に、さまざまな WCF 構成オプションに慣れていないユーザーは、少なくとも使用を開始するために、既定値を受け入れることに満足しています。
既定のエンドポイント
WCF 3.x では、エンドポイントが構成されていないサービスをホストしようとすると、ServiceHost インスタンスは、少なくとも 1 つのエンドポイントを構成する必要があることを通知する例外をスローします。 WCF 4 では、ランタイムによって自動的に 1 つ以上の "既定のエンドポイント" が自動的に追加され、構成なしでサービスが使用可能になるため、この問題はなくなりました。
しくみは次のとおりです。 ホスト アプリケーションは、ServiceHost インスタンスで Open を呼び出すと、アプリケーション構成ファイルから内部サービスの説明を、ホスト アプリケーションが明示的に構成した可能性があるものと共にビルドし、構成されたエンドポイントの数がまだ 0 の場合は、ServiceHost クラスで見つかった新しいパブリック メソッドである AddDefaultEndpoints を呼び出します。 このメソッドは、サービスのベース アドレスに基づいて 1 つ以上のエンドポイントをサービスの説明に追加します (IIS のシナリオでは、これは .svc アドレスです)。 メソッドはパブリックであるため、カスタム ホスティング シナリオで直接呼び出すこともできます。
正確には、AddDefaultEndpoints の実装では、サービスによって実装されるサービス コントラクトごとに、ベース アドレスごとに 1 つの既定のエンドポイントが追加されます。 たとえば、サービスが 2 つのサービス コントラクトを実装し、1 つのベース アドレスでホストを構成した場合、AddDefaultEndpoints は 2 つの既定のエンドポイント (サービス コントラクトごとに 1 つ) を使用してサービスを構成します。 ただし、サービスが 2 つのサービス コントラクトを実装し、ホストが 2 つのベース アドレス (1 つは HTTP 用、もう 1 つは TCP 用) で構成されている場合、AddDefaultEndpoints は 4 つの既定のエンドポイントでサービスを構成します。
完全な例を見て、これが機能することを説明しましょう。 次の WCF サービス コントラクトと次のサービス実装があるとします。
[ServiceContract]
パブリック インターフェイス IHello
{
[OperationContract]
void SayHello(string name);
}
[ServiceContract]
パブリック インターフェイス IGoodbye
{
[OperationContract]
void SayGoodbye(string name);
}
public クラス GreetingService : IHello、IGoodbye // サービスは両方のコントラクトを実装します
{
public void SayHello(string name)
{
Console.WriteLine("Hello {0}", name);
}
public void SayGoodbye(string name)
{
Console.WriteLine("Goodbye {0}", name);
}
}
WCF 4 では、ServiceHost を使用して、アプリケーション構成なしで GreetingService サービスをホストできるようになりました。 カスタム ホスティング シナリオで ServiceHost を使用する場合は、使用する 1 つ以上のベース アドレスを指定する必要があります。 次に、コンソール アプリケーションで GreetingService をホストする方法を示します。また、このプログラムに関連付けられているapp.config ファイルがないと想定できます。
クラス Program
{
static void Main(string[] args)
{
ホストは 2 つのベース アドレスで構成されます。1 つは HTTP 用、もう 1 つは TCP 用です
ServiceHost ホスト = 新しい ServiceHost(typeof(GreetingService)
new Uri("https://localhost:8080/greeting"),
new Uri("net.tcp://localhost:8081/greeting"));
ホスト。Open();
foreach (ServiceEndpoint se in host.Description.Endpoints)
Console.WriteLine("A: {0}, B: {1}, C: {2}",
Se。住所、se.Binding.Name、se.Contract.Name);
Console.WriteLine("Enter> キーを押して<サービスを停止します。);
Console.ReadLine();
ホスト。Close();
}
}
この例では、2 つのベース アドレスを使用して ServiceHost を構成します。1 つは HTTP 用、もう 1 つは TCP 用です。 このプログラムを実行すると、図 2 に示すように、コンソール ウィンドウに 4 つのエンドポイントが出力されます。 HTTP ベース アドレスには 2 つ、コントラクトごとに 1 つ、TCP ベース アドレスには 2 つ、コントラクトごとに 1 つを取得します。 これはすべて、ServiceHost インスタンスによってバックグラウンドで提供されます。
図 2: コンソール ウィンドウに表示される既定のエンドポイント
WCF が既定の HTTP エンドポイントに BasicHttpBinding を使用し、既定の TCP エンドポイントに NetTcpBinding を使用する方法に注目してください。 これらの既定値をすぐに変更する方法について説明します。
この既定のエンドポイント動作は、サービスがエンドポイントで構成されていない場合にのみ開始されることに注意してください。 少なくとも 1 つのエンドポイントでサービスを構成するようにコンソール アプリケーションを変更すると、出力にこれらの既定のエンドポイントが表示されなくなります。 これを説明するために、ServiceHost インスタンスを構築した後に AddServiceEndpoint を呼び出す次のコード行を追加します。
...
ServiceHost ホスト = 新しい ServiceHost(typeof(GreetingService)
new Uri("https://localhost:8080/greeting"),
new Uri("net.tcp://localhost:8081/greeting"));
ホスト。AddServiceEndpoint(typeof(IHello), new WSHttpBinding(), "myendpoint");
...
このコード行を挿入してコンソール アプリケーションを実行すると、1 つのエンドポイントのみが出力に表示されます。これは、上記のコードで手動で構成したものです (図 3 を参照)。
図 3: 単一のエンドポイントでホストを構成した後のコンソール出力
ただし、既定のエンドポイントのセットを独自のエンドポイントと共に追加する場合は、いつでも自分で AddDefaultEndpoints を呼び出すことができます。 次のコード例は、これを行う方法を示しています。
...
ServiceHost host = new ServiceHost(typeof(GreetingService),
new Uri("https://localhost:8080/greeting"),
new Uri("net.tcp://localhost:8081/greeting"));
ホスト。AddServiceEndpoint(typeof(IHello), new WSHttpBinding(), "myendpoint");
ホスト。AddDefaultEndpoints();
...
この変更でコンソール アプリケーションを再度実行すると、コンソール ウィンドウに 5 つのエンドポイント (4 つの既定のエンドポイントと共に手動で構成したエンドポイント) が表示されます (図 4 を参照)。
図 4: AddDefaultEndpoints を手動で呼び出した後のコンソール出力
実行時にサービスに既定のエンドポイントを追加するためのアルゴリズムとメカニズムを理解したので、次の質問は、特定のベース アドレスに使用するバインディングを WCF で決定する方法です。
既定のプロトコル マッピング
この質問に対する答えは簡単です。 WCF では、トランスポート プロトコル スキーム (http、net.tcp、net.pipe など) と組み込みの WCF バインディング間の既定のプロトコル マッピングを定義します。 既定のプロトコル マッピングは、.NET 4 machine.config.comments ファイルにあります。次のようになります。
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="basicHttpBinding" bindingConfiguration="" />
<add scheme="net.tcp" binding="netTcpBinding" bindingConfiguration=""/>
<add scheme="net.pipe" binding="netNamedPipeBinding" bindingConfiguration=""/>
<add scheme="net.msmq" binding="netMsmqBinding" bindingConfiguration=""/>
</protocolMapping>
...
マシン レベルでこれらのマッピングをオーバーライドするには、このセクションを machine.config に追加し、各プロトコル スキームのマッピングを変更します。 または、アプリケーションのスコープ内でのみオーバーライドする場合は、アプリケーション/Web 構成ファイル内でこのセクションをオーバーライドできます。
たとえば、organizationが主に WCF を使用した RESTful サービスの構築に重点を置いている場合は、"http" プロトコル スキームの既定のバインドを WebHttpBinding に変更することをお勧めします。 次の例は、アプリケーション構成ファイル内でこれを行う方法を示しています。
<構成>
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
</system.serviceModel>
</構成>
ここで、このapp.configで前に示したコンソール アプリケーションを再実行すると、2 つの既定の HTTP ベースのエンドポイントに、WebHttpBinding を使用していることが示されます (図 5 を参照)。
図 5: 既定の HTTP プロトコル マッピングをオーバーライドした後のコンソール出力
WCF は、プロトコル マッピング テーブルを介して使用するバインディングを決定すると、既定のエンドポイントを構成するときに既定のバインド構成を使用します。 組み込みのバインドの既定値に満足できない場合は、特定のバインドの既定の構成をオーバーライドすることもできます。
既定のバインド構成
すべての WCF バインディングには、特定のエンドポイントのホスト アプリケーションによって明示的にオーバーライドされない限り、使用される既定の構成が付属しています。 明示的なバインド構成を適用してオーバーライドすることを選択しない限り、使用する各バインド インスタンスには常に組み込みの既定値が付属しています。
WCF 3.x では、bindingConfiguration 属性を使用してエンドポイント定義に適用できる名前付きバインド構成を定義することで、これを行います。 これを適切に行う仕組みは面倒でエラーが発生しやすいです。 次の構成ファイルは、一般的な例を示しています。
<構成>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicWithMtom" messageEncoding="Mtom"/>
</basicHttpBinding>
</バインド>
<services>
<サービス名="GreetingService">
<endpoint address="mtom" binding="basicHttpBinding"
bindingConfiguration="BasicWithMtom"
contract="IHello"/>
</service>
</サービス>
</system.serviceModel>
</構成>
上記の例では、"BasicWithMtom" バインド構成は、メッセージ エンコードを MTOM に変更することで、BasicHttpBinding の既定値をオーバーライドします。 ただし、このバインド構成は、"bindingConfiguration" 属性を使用して特定のエンドポイントに適用する場合にのみ有効になります。これは、開発者や運用スタッフを排除する手順であり、構成の問題が発生します。
WCF 4 では、新しい構成を定義するときにバインド構成名を省略するだけで、既定のバインド構成を定義できるようになりました。 その後、WCF は、明示的なバインド構成が設定されていないバインディングを使用するすべてのエンドポイントに対して、その既定の構成を使用します。
たとえば、前に示したコンソール アプリケーションに次のapp.config ファイルを追加すると、2 つの既定の HTTP エンドポイントでこの既定の BasicHttpBinding 構成が選択され、MTOM が有効になります。
<構成>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding messageEncoding="Mtom"/><--名前属性がないことに注意してください -->
</basicHttpBinding>
</バインド>
</system.serviceModel>
</構成>
もちろん、コンピューター上で実行されているすべてのサービスでこれらの既定のバインド構成を有効にする場合や、アプリケーション構成ファイル内に既定のバインド構成を追加してアプリケーションごとに定義する場合は、これらの既定のバインド構成をmachine.configに追加することもできます。
この機能により、バインド構成の複雑さを他の開発者や IT/運用スタッフに課すことなく、すべてのサービスで使用できる標準のバインドの既定値セットを定義するための簡単なメカニズムが提供されます。 適切なバインディングを選択するだけで、適切な既定の構成がホスティング環境によって提供されます。
既定のバインド構成に加えて、サービスとエンドポイントに対して考慮すべきもう 1 つの点は、既定の動作構成です。
既定の動作の構成
WCF 4 では、サービスとエンドポイントの既定の動作構成を定義することもできます。これにより、コンピューター上またはソリューション内で実行されているすべてのサービスまたはエンドポイントで標準の既定の動作構成を共有する場合に簡略化できます。
WCF 3.x では、"behaviorConfiguration" 属性を使用してサービスとエンドポイントに明示的に適用する名前付き動作構成を定義する必要があります。 WCF 4 では、構成定義で名前を省略することで、既定の動作構成を定義できます。 これらの既定の動作をmachine.configに追加すると、マシンでホストされているすべてのサービスまたはエンドポイントに適用されます。 app.configに追加すると、ホスト アプリケーションのスコープ内でのみ有効になります。 次に例を示します。
<構成>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<動作><--名前属性がないことに注意してください -->
<serviceMetadata httpGetEnabled="true"/>
</動作>
</serviceBehaviors>
</動作>
</system.serviceModel>
</構成>
この例では、明示的な動作構成が付属していないサービスのサービス メタデータを有効にします。 前に示したコンソール アプリケーションのapp.config ファイルにこの既定の動作構成を追加し、アプリケーションをもう一度実行すると、ベース HTTP アドレスを参照してサービス ヘルプ ページとサービスの WSDL 定義を取得できます (図 6 を参照)。
図 6: 既定の動作構成で有効になっているサービス メタデータの参照
WCF 4 のもう 1 つの新機能は、動作構成で継承モデルがサポートされるようになりました。 machine.configで既に定義されている名前と同じ名前を使用してアプリケーションで動作構成を定義した場合、アプリケーション固有の動作構成はマシン全体の構成とマージされ、派生複合動作構成に動作が追加されます。
標準エンドポイント
既定のエンドポイントに関連する、"標準エンドポイント" と呼ばれるもう 1 つの新しい WCF 4 機能です。 標準エンドポイントは、単に使用できる WCF 4 フレームワークに組み込まれている共通の事前構成済みエンドポイント定義と考えることができます。 標準エンドポイントでは、通常は変更しない "標準" エンドポイント構成を定義しますが、必要に応じてすぐに確認できます。
図 7 では、WCF 4 に付属する標準エンドポイントについて説明します。 これらは、WCF 4 の最も一般的な機能と通信シナリオの一部の標準エンドポイント定義を提供します。 たとえば、MEX エンドポイントの場合は、常にサービス コントラクトに IMetadataExchange を指定する必要があり、HTTP を選択する可能性が最も高くなります。 そのため、WCF では、常に手動で行う代わりに、"mexEndpoint" と呼ばれる metdata 交換用の標準エンドポイント定義が用意されています。これは使いやすいです。
図 7: WCF 4 の標準エンドポイント
標準エンドポイント名 | 説明 |
---|---|
mexEndpoint |
サービス コントラクトに対して IMetadataExchange を使用して構成された MEX の標準エンドポイント、既定のバインディングとして mexHttpBinding (これを変更できます)、空のアドレスを定義します。 |
dynamicEndpoint |
WCF クライアント アプリケーション内で WCF Discovery を使用するように構成された標準エンドポイントを定義します。 この標準エンドポイントを使用する場合、アドレスは必要ありません。これは、最初の呼び出し時に、クライアントが指定したコントラクトに一致するサービス エンドポイントを照会し、自動的に接続するためです。 既定では、探索クエリはマルチキャスト UDP 経由で送信されますが、必要なときに使用する探索バインディングと検索条件を指定できます。 |
discoveryEndpoint |
クライアント アプリケーション内の検出操作用に事前に構成された標準エンドポイントを定義します。 この標準エンドポイントを使用する場合、ユーザーはアドレスとバインドを指定する必要があります。 |
udpDiscoveryEndpoint |
マルチキャスト アドレスで UDP バインディングを使用して、クライアント アプリケーション内の検出操作用に事前に構成された標準エンドポイントを定義します。 DiscoveryEndpoint から派生します。 |
announcementEndpoint |
検出のアナウンス機能用に事前に構成された標準エンドポイントを定義します。 この標準エンドポイントを使用する場合、ユーザーはアドレスとバインドを指定する必要があります。 |
udpAnnouncementEndpoint |
マルチキャスト アドレスでの UDP バインディングに対するアナウンス機能用に事前に構成された標準エンドポイントを定義します。 このエンドポイントは announcementEndpoint から派生します。 |
workflowControlEndpoint |
ワークフロー インスタンスの実行の制御 (作成、実行、保留、終了など) に使用する標準エンドポイントを定義します。 |
webHttpEndpoint |
WebHttpBinding と WebHttpBehavior で構成された標準エンドポイントを定義します。 REST サービスを公開するには、 を使用します。 |
webScriptEndpoint |
WebHttpBinding と WebScriptEnablingBehavior で構成された標準エンドポイントを定義します。 を使用して Ajax サービスを公開します。 |
これらの標準エンドポイントは、名前で参照するだけで、独自のサービス構成で利用できます。 エンドポイント>要素には<、標準エンドポイントの名前を指定するために使用できる "kind" 属性が付属するようになりました。 たとえば、次の例では、標準の "mexEndpoint" 定義を利用して、MEX エンドポイントを使用して GreetingService を構成します。
<構成>
<system.serviceModel>
<services>
<service name="GreetingService">
<endpoint kind="basicHttpBinding" contract="IHello"/>
<endpoint kind="mexEndpoint" address="mex" />
</service>
</サービス>
</system.serviceModel>
</構成>
標準エンドポイントはほとんどの構成の詳細から保護されますが (たとえば、mexEndpoint ではバインディングやコントラクトを指定する必要はありませんでした)、それらを使用したいが、標準エンドポイント定義を少し異なる方法で構成する必要がある場合があります。
これを行う必要がある場合は、standardEndpoints> セクションを<使用し、標準エンドポイントのエンドポイント構成をオーバーライドできます。 次に示すように、endpointConfiguration 属性を使用して新しい <エンドポイント> を定義するときに、その構成を参照できます。
<構成>
<system.serviceModel>
<services>
<service name="GreetingService">
<endpoint binding="basicHttpBinding" contract="IHello"/>
<endpoint kind="udpDiscoveryEndpoint" endpointConfiguration="D11"/>
</service>
</サービス>
<standardEndpoints>
<udpDiscoveryEndpoint>
<standardEndpoint name="D11" discoveryVersion="WSDiscovery11"/>
</udpDiscoveryEndpoint>
</standardEndpoints>
<behaviors>
<serviceBehaviors>
<動作>
<serviceDiscovery/>
<serviceMetadata httpGetEnabled="true"/>
</動作>
</serviceBehaviors>
</動作>
</system.serviceModel>
</構成>
この例では、"udpDiscoveryEndpoint" という名前の標準エンドポイントの既定のWS-Discoveryバージョンを変更します (サービス検出の詳細については、まもなく説明します)。
IIS/ASP.NET ホスティングの簡略化
既定のエンドポイント、既定のバインド構成、既定の動作構成に対するこれらの新機能により、WCF 4 では IIS/ASP.NET でのホストがはるかに簡単になります。 ASMX サービスの操作に慣れている ASP.NET 開発者は、本質的に単純な WCF サービスを定義できるようになりました。
実際、次の WCF サービス定義がいかに単純であるかをチェックします。
<HelloWorld.svc を--する -->
<%@ ServiceHost Language="C#" Debug="true" Service="HelloWorldService
CodeBehind="~/App_Code/HelloWorldService.cs" %>
[ServiceContract]
public クラス HelloWorldService
{
[OperationContract]
パブリック文字列 HelloWorld()
{
"hello, world" を返します。
}
}
これは WCF サービス定義の最も簡単な形式です。これは、サービス コントラクトを定義するために別のインターフェイス定義を使用せず、すべてが 1 つのファイル HelloWorld.svc で定義されているためです (注: ASMX との比較を描画することは可能であることに注意してください)。 これは一般的な ASMX サービスとよく似ているはずです。主な違いは、サービス クラスで使用する属性名 (例: [WebService] と [WebMethod]) です。 可動部分は確実に少なくなります。
前のセクションで説明した新しい WCF 4 機能を使用すると、追加の WCF 構成なしで HelloWorld.svc を参照できるようになりました。WCF アクティブ化ロジックによって、背後に ServiceHost インスタンスが作成され、単一の既定の HTTP エンドポイントで構成されます。 また、サービス メタデータを有効にするmachine.config ファイルに既定のサービス動作を追加した場合は、HelloWorld.svc を参照するときに WCF ヘルプ ページと WSDL 定義へのリンクが表示されます (図 8 を参照)。
図 8: HelloWorldService のヘルプ ページ
マシン全体でサービス メタデータを有効にしていない場合は、次の既定の動作構成を web.config ファイルに追加することで、Web アプリケーション内で有効にすることができます。
...
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior><--名前属性がないことに注意してください-->
<serviceMetadata httpGetEnabled="true"/>
</動作>
</serviceBehaviors>
</動作>
</system.serviceModel>
...
前のセクションで説明した手順に従って、他の既定の設定を変更することもできます。 たとえば、既定のプロトコル マッピングを変更したり、既定のバインド構成を追加したり、既定の動作構成を追加したりできます。 サービスが複数のサービス コントラクトを実装する場合、結果の ServiceHost インスタンスはコントラクトごとに 1 つの HTTP エンドポイントで構成されます。
たとえば、次に示す .svc ファイルを使用して GreetingService を (以前のバージョンから) ホストするとします。
<GreetingService.svc を--する -->
<%@ServiceHost Service="GreetingService"%>
GreetingService の定義を指定すると、GreetingService.svc を初めて参照すると、WCF アクティブ化ロジックによって ServiceHost インスタンスが作成され、GreetingService 型 (サービス コントラクトごとに 1 つ) に 2 つの既定の HTTP エンドポイントが追加されます。 これを確認するには、WSDL 定義を参照すると、サービス>要素内に 2 つの<ポート>要素があります<。
全体的に、これらの WCF 構成の簡略化により、ASP.NET 開発者は Web アプリケーション内で WCF サービスを簡単に起動して実行でき、ASP.NET Web サービスで開発者が慣れていたエクスペリエンスに最も簡単なケースが大幅に近づくはずです。
ファイルレスアクティブ化
.svc ファイルを使用すると WCF サービスを簡単に公開できますが、さらに簡単な方法は、Web.config内で仮想アクティブ化エンドポイントを定義することで、.svc ファイルの必要性を完全に排除することです。
WCF 4 では、Web.configでサービスの種類にマップされる仮想サービスアクティブ化エンドポイントを定義できます。これにより、物理的な .svc ファイル ("ファイルなしのアクティブ化") を維持することなく、WCF サービスをアクティブ化できます。 次の例は、アクティブ化エンドポイントを構成する方法を示しています。
<構成>
<system.serviceModel>
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="Greeting.svc" service="GreetingService"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
</構成>
これで、"Greeting.svc" の相対パス (Web アプリケーションのベース アドレスに対する相対パス) を使用して GreetingService をアクティブ化できるようになりました。 これを説明するために、"GreetingSite" という名前の IIS アプリケーションを自分のコンピューターに作成しました。このアプリケーション プールを "ASP.NET v4.0" アプリケーション プールに割り当て、上に示したweb.configを含む GreetingService プロジェクト ディレクトリにマップしました。 今、私は実際にディスク上に https://localhost/GreetingSite/Greeting.svc 物理的な.svcファイルを持たずにを参照することができます。 図 9 は、ブラウザーでのこの外観を示しています。
図 9: ファイルレスアクティブ化の例
探索
次に説明する WCF 4 の主な機能は、サービス検出です。 一部の特殊なサービス指向環境では、ランタイムの場所が動的で絶えず変化するサービスがあります。 たとえば、さまざまな種類のサービス対応デバイスが、ビジネス ソリューション全体の一部としてネットワークに絶えず参加および退出している環境を考えてみましょう。 この現実を処理するには、クライアントがサービス エンドポイントのランタイムの場所を動的に検出する必要があります。
WS-Discoveryは、実行時にサービス エンドポイントの場所を動的に検出するための SOAP ベースのプロトコルを定義する OASIS 仕様です。 プロトコルを使用すると、クライアントは、適切な候補の一覧を取得するために、特定の条件に一致するサービス エンドポイントをプローブできます。 クライアントは、検出された一覧から特定のエンドポイントを選択し、現在のランタイム エンドポイント アドレスを使用できます。
WS-Discoveryでは、アドホック モードとマネージド モードの 2 つの主要な操作モードを定義します。 アドホック モードでは、クライアントはマルチキャスト メッセージを送信してサービスをプローブします。 フレームワークは、このアドホック モード用の UDP マルチキャスト メカニズムを提供します。 プローブに一致するサービスは、クライアントに直接応答します。 クライアント ポーリングの必要性を最小限に抑えるために、"リッスンしている" 可能性のあるクライアントにマルチキャスト メッセージを送信することで、サービスがネットワークに参加または退出するときに自身を "読み上げる" こともできます。 アドホック検出は、メッセージのマルチキャストに使用されるプロトコルによって制限されます。UDP の場合、ローカル サブネットでリッスンしているサービスのみがメッセージを受信できます。
マネージド サービス検出では、検出可能なサービス エンドポイントを "管理" する探索プロキシをネットワーク上に提供します。 クライアントは検出プロキシと直接通信し、プローブ条件に基づいてサービスを検索します。 探索プロキシには、クエリと照合できるサービスのリポジトリが必要です。 プロキシにこの情報を入力する方法は、実装の詳細です。 探索プロキシは、エグジティング サービス リポジトリに簡単に接続できます。また、エンドポイントの一覧を使用して事前に構成することも、探索プロキシでキャッシュの更新に関するお知らせをリッスンすることもできます。 マネージド モードでは、お知らせは受信者に直接ユニキャストでき、検出プロキシによって直接送信される可能性があります。
.NET 4.0 フレームワークには、独自の探索プロキシを実装するために必要な基本クラスが用意されています。 基底クラスは探索プロトコルの詳細を抽象化するため、探索プロキシに含めるロジックに集中できます。 たとえば、探索プロキシがプローブ メッセージ、アナウンス メッセージ、およびメッセージの解決に応答して行う処理のみを定義する必要があります。
WCF 4 では、WS-Discovery プロトコルの完全な実装が提供され、アドホック検出モードとマネージド検出モードの両方がサポートされます。 以下では、それぞれについて簡単に説明します。
単純なサービス検出
サービス検出を有効にする最も簡単な方法は、アドホック モードを使用することです。 WCF を使用すると、いくつかの標準的な検出エンドポイントとサービス検出動作を提供することで、サービス ホスト アプリケーション内でサービス検出を簡単に有効にすることができます。 サービスを探索用に構成するには、標準の "udpDiscoveryEndpoint" エンドポイントを追加し、サービスで <サービスのDiscovery> 動作を有効にします。
これを行う方法を示す完全な例を次に示します。
<構成>
<system.serviceModel>
<services>
<service name="CalculatorService">
<endpoint binding="wsHttpBinding" contract="ICalculatorService" />
<標準の UDP 検出エンドポイントを追加--->
<endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>
</service>
</サービス>
<behaviors>
<serviceBehaviors>
<動作>
<serviceDiscovery/><-- サービス検出動作を有効にする -->
</動作>
</serviceBehaviors>
</動作>
</system.serviceModel>
</構成>
これにより、サービスはローカル サブネット上の UDP 経由で検出できるようになります。 クライアントは実行時にWS-Discoveryを利用して、実行中のサービスの実際のアドレスを "検出" できます。 WCF 4 を使用すると、クライアントは dynamicEndpoint 標準エンドポイントを使用してこれを簡単に実行できます。
サービスへの接続に使用していた既存のクライアント エンドポイントを取得し、アドレスを削除して kind="dynamicEndpoint" タグを追加するだけです。
<構成>
<system.serviceModel>
<client>
<エンドポイント
name="calculatorEndpoint"
kind="dynamicEndpoint"
binding="wsHttpBinding"
contract="ICalculatorService">
</エンドポイント>
</クライアント>
</system.serviceModel>
</構成>
最初のサービス呼び出しが行われると、クライアントは、ICalculatorService コントラクトに一致するサービスを探してマルチキャスト クエリを送信し、1 つへの接続を試みます。 さまざまな設定を使用すると、serach を微調整したり、検出バインドを調整したり、検出プロセスを制御したりできます。 このすべてをプログラムで行うには、DiscoveryClient クラスを使用します。
次の例では、UdpDiscoveryEndpoint をプログラムで使用して ICalculatorService エンドポイントを検出し、それを呼び出す方法を示すことで、さらに 1 ステップ進みます。
DiscoveryClient の作成
DiscoveryClient discoveryClient =
new DiscoveryClient(new UdpDiscoveryEndpoint());
指定したスコープで ICalculatorService エンドポイントを検索する
FindCriteria findCriteria = new FindCriteria(typeof(ICalculatorService));
FindResponse findResponse = discoveryClient.Find(findCriteria);
最初に検出されたエンドポイントを選択するだけです
EndpointAddress address = findResponse.Endpoints[0]。アドレス;
ターゲット サービス クライアントを作成する
CalculatorServiceClient クライアント =
new CalculatorServiceClient("calculatorEndpoint");
検出されたサービス エンドポイントに接続する
クライアント。Endpoint.Address = address;
Console.WriteLine("CalculatorService {0}を ", address);
サービスの追加操作を呼び出します。
double result = client。Add(100, 15.99);
Console.WriteLine("Add({0},{1}) = {2}", 100, 15.99, result);
クライアント プログラムは、検出されたエンドポイントのコレクションを取得したら、そのうちの 1 つを使用して、ターゲット サービスを実際に呼び出すことができます。 図 10 は、サービスも同時に実行されていることを前提として、上記のクライアント コードを実行する出力を示しています。 注: この例では、探索クライアントの検索操作は同期です。検出では、非同期検索操作もサポートされます。
図 10: 探索クライアント コードの実行の出力
エンドポイントの検出時のスコープの使用
前の例では、クライアントは単にサービス コントラクトの種類に基づいてサービスをプローブしました。 クライアントは、探索プローブの送信時に追加のスコープ情報を提供することで、検出結果を絞り込むことができます。 簡単な例を見て、検出中に "スコープ" を使用する方法を見てみましょう。
最初に、サービスは、検出のために発行する各エンドポイントに 1 つ以上のスコープを関連付ける必要があります。 WCF 4 には、 <エンドポイント定義に関連付けることができる一連のスコープを定義するために使用できるエンドポイント情報開示> 動作が付属しています。 次の例は、サービスで定義されている単一のエンドポイントに 2 つのスコープを関連付ける方法を示しています。
<構成>
<system.serviceModel>
<services>
<service name="CalculatorService"
behaviorConfiguration="calculatorServiceBehavior">
<endpoint binding="wsHttpBinding"
contract="ICalculatorService"
behaviorConfiguration="ep1Behavior" />
<endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>
</service>
</サービス>
<behaviors>
<serviceBehaviors>
<behavior name="calculatorServiceBehavior">
<serviceDiscovery/>
</動作>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="ep1Behavior">
<endpointDiscovery>
<このエンドポイントの動作に関連付けられているスコープを--する -->
<scopes>
<add scope="http://www.example.org/calculator"/>
<add scope="ldap:///ou=engineering,o=exampleorg,c=us"/>
</スコープ>
</endpointDiscovery>
</動作>
</endpointBehaviors>
</動作>
</system.serviceModel>
</構成>
クライアントは、実行時に特定のスコープに基づいてサービス エンドポイントをプローブできます。 これを行うには、Find 操作に指定した FindCriteria インスタンスにターゲット スコープの一覧を追加します。 次のコードは、特定の LDAP スコープに一致する ICalculatorService エンドポイントを検出する方法を示しています。
...
DiscoveryClient の作成
DiscoveryClient discoveryClient = new DiscoveryClient("udpDiscoveryEndpoint");
指定したスコープで ICalculatorService エンドポイントを検索する
Uri スコープ = 新しい Uri("ldap:///ou=engineering,o=exampleorg,c=us");
FindCriteria findCriteria = new FindCriteria(typeof(ICalculatorService));
findCriteria.Scopes.Add(scope);
FindResponse findResponse = discoveryClient.Find(findCriteria);
...
スコープを利用すると、クライアントが対象の特定のサービス エンドポイントをより簡単に検出できるように、検出の実装を微調整できます。 検出を使用すると、さらにカスタマイズすることもできます。 たとえば、サービスはカスタム XML メタデータをエンドポイントに追加できます。 この情報は、クライアントのクエリに応答してクライアントに送信されます。
サービスのお知らせ
WCF 4 では、起動時にエンドポイントを "読み上げる" ようにサービスを簡単に構成できます。 これにより、"リッスン" しているクライアントは、ネットワークに参加するときに新しいサービス エンドポイントについて理解できるため、クライアントによって実行されるプローブ (およびマルチキャスト メッセージング) の量を減らすことができます。
サービス情報開示>の動作を使用して、アナウンス エンドポイントを使用してサービスを<構成できます。 <サービスの情報開示>動作を使用すると、サービスによって公開されるアナウンス エンドポイントのコレクションを定義できます。 ほとんどの場合、標準の "udpAnnouncementEndpoint" を使用できます。
また、クライアントによって開始された探索プローブに応答する場合は、標準の "udpDiscoveryEndpoint" を使用してサービスを構成する必要もあります。 次の例は、一般的な構成を示しています。
<構成>
<system.serviceModel>
<services>
<service name="CalculatorService">
<endpoint binding="wsHttpBinding" contract="ICalculatorService"/>
<endpoint kind="udpDiscoveryEndpoint"/>
</service>
</サービス>
<behaviors>
<serviceBehaviors>
<動作>
<serviceDiscovery>
<announcementEndpoints>
<endpoint kind="udpAnnouncementEndpoint"/>
</announcementEndpoints>
</serviceDiscovery>
</動作>
</serviceBehaviors>
</動作>
</system.serviceModel>
</構成>
この構成が整うと、サービスはオンラインになると自動的に読み上げられ、オフラインになるとも読み上げられるようになります。 これらのお知らせを利用するには、実行時にリッスンするようにクライアントを特別に設計する必要があります。 これを行うには、WS-Discoveryアナウンス プロトコルを実装するクライアント アプリケーション内でアナウンス サービスをホストします。
WCF 4 には、この目的のために特別に設計された AnnouncementService というクラスが付属しています。 AnnouncementService には、OnlineAnnouncementReceived と OfflineAnnouncementReceived の 2 つのイベント ハンドラーが用意されています。 クライアント アプリケーションでは、ServiceHost を使用して AnnouncementService のインスタンスをホストし、これら 2 つのイベントのイベント ハンドラーを登録できます。
サービスがオンラインになり、それ自体が読み上げられるたびに、クライアントでホストされる AnnouncementService は "オンライン" のお知らせを受け取り、OnlineAnnouncementReceived がクライアントで起動します。 サービスがオフラインになると、"オフライン" のお知らせが送信され、OfflineAnnouncementReceived がクライアントで起動します。 次に、AnnouncementService をホストし、2 つのアナウンス イベントのハンドラーを実装するサンプル クライアント アプリケーションを示します。
クラス クライアント
{
public static void Main()
{
AnnouncementService インスタンスを作成する
AnnouncementService announcementService = new AnnouncementService();
アナウンス イベントをサブスクライブする
announcementService.OnlineAnnouncementReceived += OnOnlineEvent;
announcementService.OfflineAnnouncementReceived += OnOfflineEvent;
AnnouncementService の ServiceHost を作成する
using (ServiceHost announcementServiceHost =
new ServiceHost(announcementService))
{
UDP マルチキャスト経由で送信されたアナウンスをリッスンする
announcementServiceHost.AddServiceEndpoint(
new UdpAnnouncementEndpoint());
announcementServiceHost.Open();
Console.WriteLine("Listening for service announcements.");
Console.WriteLine();
Console.WriteLine("Enter キー>を押して<終了します。);
Console.ReadLine();
}
}
static void OnOnlineEvent(object sender, AnnouncementEventArgs e)
{
Console.WriteLine();
Console.WriteLine("Received an online announcement from {0}:",
e.EndpointDiscoveryMetadata.Address);
PrintEndpointDiscoveryMetadata(e.EndpointDiscoveryMetadata);
}
static void OnOfflineEvent(object sender, AnnouncementEventArgs e)
{
Console.WriteLine();
Console.WriteLine(":"からオフラインアナウンス {0}を受信しました",
e.EndpointDiscoveryMetadata.Address);
PrintEndpointDiscoveryMetadata(e.EndpointDiscoveryMetadata);
}
...
}
図 11: 検出アナウンス メッセージのリッスン
次に、このクライアント プログラムを実行し、しばらくの間実行したままにしたとします。 その後、サービス ホスト アプリケーションのいくつかのインスタンスを実行します。 各メッセージが起動すると、クライアント コンソール ウィンドウに "オンライン" のアナウンスメッセージが表示されます。 各サービス ホスト アプリケーションを閉じると、クライアント コンソール ウィンドウに "オフライン" のお知らせメッセージが表示されます。 図 11 は、先ほど説明したことを行った後の結果のクライアント コンソール ウィンドウを示しています。
アドホック検出モードはローカル サブネットでのみ機能します。 ローカル ネットワークの境界を超えてWS-Discoveryを使用する場合は、マネージド検出モードに切り替える必要があります。 WCF 4 では、必要なマネージド検出コンポーネントの構築もサポートされています。
マネージド サービスの検出
マネージド探索モードの実装は、探索プロキシ サービスを実装する必要があるため、アドホック モードよりも少し複雑です。 探索プロキシ サービスは、使用可能なすべてのサービス エンドポイントを追跡するコンポーネントです。 この例では、アナウンス機能を使用して探索プロキシを更新します。 関連する検出情報を探索プロキシに提供するには、他にも多くの方法があります。たとえば、エンドポイントの既存のデータベースに接続し、そこからデータをキャプチャできます。 では、探索プロキシ サービスを実装するにはどうすればよいですか?
WCF 4 には、探索プロキシ サービスを実装するためにから派生できる DiscoveryProxy という名前の基本クラスが付属しています。 図 12 は、カスタム探索プロキシ サービスの実装の開始を示しています。 .NET 4 SDK サンプルには、参照用の完全なサンプル実装が含まれています。 探索プロキシ サービスの実装が完了したら、どこかでホストする必要があります。
図 12: カスタム探索プロキシ サービスの実装
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public クラス MyDiscoveryProxy : DiscoveryProxyBase
{
EndpointDiscoveryMetadata を格納するリポジトリ。
代わりに、データベースまたはフラット ファイルを使用することもできます。
Dictionary<EndpointAddress、EndpointDiscoveryMetadata> onlineServices;
public MyDiscoveryProxy()
{
this.onlineServices =
新しい Dictionary<EndpointAddress、EndpointDiscoveryMetadata>();
}
OnBeginOnlineAnnouncement は、プロキシによって Hello メッセージを受信したときに呼び出されます
protected override IAsyncResult OnBeginOnlineAnnouncement(
DiscoveryMessageSequence messageSequence、EndpointDiscoveryMetadata
endpointDiscoveryMetadata、AsyncCallback コールバック、オブジェクトの状態)
{
これ。AddOnlineService(endpointDiscoveryMetadata);
return new OnOnlineAnnouncementAsyncResult(callback, state);
}
protected override void OnEndOnlineAnnouncement(IAsyncResult result)
{
OnOnlineAnnouncementAsyncResult.End(result);
}
OnBeginOfflineAnnouncement は、Bye メッセージがプロキシによって受信されたときに呼び出されます
protected override IAsyncResult OnBeginOfflineAnnouncement(
DiscoveryMessageSequence messageSequence、EndpointDiscoveryMetadata
endpointDiscoveryMetadata、AsyncCallback コールバック、オブジェクトの状態)
{
これ。RemoveOnlineService(endpointDiscoveryMetadata);
新しい OnOfflineAnnouncementAsyncResult(callback, state);
}
protected override void OnEndOfflineAnnouncement(IAsyncResult result)
{
OnOfflineAnnouncementAsyncResult.End(result);
}
OnBeginFind は、プローブ要求メッセージがプロキシによって受信されたときに呼び出されます
protected override IAsyncResult OnBeginFind(
FindRequestContext findRequestContext, AsyncCallback コールバック, オブジェクトの状態)
{
これ。MatchFromOnlineService(findRequestContext);
新しい OnFindAsyncResult(callback, state);
}
protected override void OnEndFind(IAsyncResult result)
{
OnFindAsyncResult.End(result);
}
...
この例では、単にコンソール アプリケーションで MyDiscoveryProxy サービスをホストします。 探索エンドポイントとアナウンス エンドポイントの 2 つのエンドポイントを使用してホストを構成します。 次の例は、これらの両方のエンドポイントで MyDiscoveryProxy サービスを適切にホストする方法を示しています。
クラス Program
{
public static void Main()
{
Uri probeEndpointAddress = new Uri("net.tcp://localhost:8001/Probe");
Uri announcementEndpointAddress =
new Uri("net.tcp://localhost:9021/Announcement");
ServiceHost proxyServiceHost = new ServiceHost(new MyDiscoveryProxy());
DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(
new NetTcpBinding(), new EndpointAddress(probeEndpointAddress));
discoveryEndpoint.IsSystemEndpoint = false;
AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(
new NetTcpBinding(), new EndpointAddress(announcementEndpointAddress));
proxyServiceHost.AddServiceEndpoint(discoveryEndpoint);
proxyServiceHost.AddServiceEndpoint(announcementEndpoint);
proxyServiceHost.Open();
Console.WriteLine("Proxy Service started.");
Console.WriteLine();
Console.WriteLine("Enter> キーを押して<サービスを終了します。);
Console.WriteLine();
Console.ReadLine();
proxyServiceHost.Close();
}
}
探索プロキシ サービスを起動して実行したら、探索プロキシ サービスに直接読み上げるサービスを構成できます。 同様に、探索プロキシ サービスを直接プローブするようにクライアント アプリケーションを構成することもできます (これ以上マルチキャスト メッセージングはありません)。
サービス ホスト アプリケーション内で AnnouncementEndpoint を作成するときに、探索プロキシのアナウンス アドレスを指定して、探索プロキシ サービスに直接通知するようにサービスを構成します。 次の例は、これを実現する方法を示しています。
...
Uri baseAddress = new Uri("net.tcp://localhost:9002/CalculatorService/" +
Guid.NewGuid()。ToString());
Uri announcementEndpointAddress = new Uri("net.tcp://localhost:9021/Announcement");
ServiceHost serviceHost = 新しい ServiceHost(typeof(CalculatorService), baseAddress);
ServiceEndpoint netTcpEndpoint = serviceHost.AddServiceEndpoint(
typeof(ICalculatorService), new NetTcpBinding(), string.空);
ホストされているプロキシ サービスを指すアナウンス エンドポイントを作成する
AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(
new NetTcpBinding(), new EndpointAddress(announcementEndpointAddress));
ServiceDiscoveryBehavior serviceDiscoveryBehavior = 新しい ServiceDiscoveryBehavior();
serviceDiscoveryBehavior.AnnouncementEndpoints.Add(announcementEndpoint);
serviceHost.Description.Behaviors.Add(serviceDiscoveryBehavior);
serviceHost.Open();
...
その後、クライアント アプリケーション内で DiscoveryEndpoint を作成するときに探索プロキシのプローブ アドレスを指定することで、探索プロキシ サービスと直接通信するようにクライアント アプリケーションを構成できます。 次の例は、これを行う 1 つの方法を示しています。
...
プロキシ サービスを指す探索エンドポイントを作成します。
Uri probeEndpointAddress = new Uri("net.tcp://localhost:8001/Probe");
DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(
new NetTcpBinding(), new EndpointAddress(probeEndpointAddress));
前に作成した discoveryEndpoint を使用して DiscoveryClient を作成する
DiscoveryClient discoveryClient = new DiscoveryClient(discoveryEndpoint);
ICalculatorService エンドポイントを検索する
FindResponse findResponse = discoveryClient.Find(
new FindCriteria(typeof(ICalculatorService)));
...
次に、完全な例を見てみましょう。 まず、探索プロキシ アプリケーションを実行して、探索プロキシ サービスを使用できるようにします。 次に、サービス ホスト アプリケーションのインスタンスを実行します。これにより、探索プロキシを使用して自身が読み上げられるようになります。 これが発生すると、検出プロキシ アプリケーションのコンソール ウィンドウにメッセージが出力されます (図 13 を参照)。 これは、サービスが検出プロキシに正常に通知され、探索プロキシが新しい "オンライン" サービス エンドポイントに関する情報を保存したことを示しています。 上記のクライアント コードを実行すると、検出プロキシが直接プローブされ、現在実行中のターゲット サービスのエンドポイント アドレスが取得されます。
図 13: 実行時の探索プロキシ サービスからの出力
マネージド サービス検出の美しさは、ネットワーク境界を越えて機能し (従来のサービス呼び出しに基づいています)、検出ソリューション内でのマルチキャスト メッセージングの必要性を減らすことです。 さらに、クライアントは探索プロキシを経由してサービスを検索するため、サービス自体を常に起動して実行する必要はありません。
高度な探索プロキシの使用
WCF プログラミング モデルを使用すると、探索プロキシを実装する際に多くの柔軟性が得られます。 お知らせを受け取る方法の 1 つは、サービスの一覧を設定する方法の 1 つです。しかし、それは唯一の方法ではありません。 たとえば、環境に既にサービス リポジトリが含まれている場合は、実行時にリポジトリを検出できるように、そのストアの上に探索プロキシ ファサードを簡単に構築できます。
検出プロキシは、アドホック モードまたは管理モードで設定できます。 マネージド モードで動作する場合、クライアントはアナウンス、プローブ、解決を使用して、ユニキャスト方式でプロキシと直接通信します。 また、プロキシはユニキャスト方式で応答を送信側に送信します。
アドホック モードで動作している場合、プロキシはマルチキャスト検出メッセージをリッスンし、送信者に直接応答できます。 このアドホック モードでは、マルチキャスト メッセージを抑制するようにプロキシを特別に構成することもできます。 つまり、プロキシがマルチキャスト メッセージを受信した場合、その存在を送信者に通知し、プロキシでさらにクエリを送信するように送信者に通知するため、さらにマルチキャスト メッセージを回避できます。
これらの高度な検出シナリオの詳細については、「WS-Discovery入門 http://www.oasis-open.org/committees/download.php/32184/WS-D-primer-wd-04.docx」を参照してください。
ルーティング サービス
一部のサービス指向環境では、ブローカーまたはゲートウェイとして機能する一元化された "ルーティング" サービスを、organizationに散在する実際のビジネス サービスに利用すると便利な場合があります。 これにより、コンシューマーが実際のビジネス サービスから切り離され、ルーティング ノード内でさまざまな種類の中間処理を実行できるようになります。
たとえば、一部の環境ではルーティングを使用して、すべての受信メッセージが通過する必要がある一元化されたセキュリティ境界を実装します。 コンテンツ ベースのルーティング手法を使用して、特定の受信メッセージの内容に基づいて使用するターゲット サービスを決定する場合があります。 他のユーザーはルーティングを使用してプロトコル ブリッジングを実装するため、コンシューマーは 1 つのプロトコル セットを使用して通信できます。ルーターは別のプロトコル セットを使用してターゲット サービスと通信します。 また、さまざまな負荷分散やサービスのバージョン管理手法にルーティングを使用することも珍しくありません。
理由が何であれ、今日の大規模な SOA ソリューションを構築する場合、"中間ルーティング" パターンが一般的な要件です。 WCF 3.x では、ルーティングの公式なサポートはありませんでした。 フレームワークは独自のルーティング サービスを実装するために必要な API を提供しましたが、これを適切に行うには多くの作業が必要でした。 これを実現する方法を示す記事がいくつか MSDN マガジンに掲載されています。
ルーティングはこのような一般的な要件であるため、WCF 4 には、独自のソリューションでホストして構成できるフレームワークに公式の "ルーティング サービス" が付属するようになりました。
RoutingService について
WCF 4 には RoutingService という新しいクラスが付属しています。これにより、アプリケーション内で使用するための汎用 WCF ルーティング実装が提供されます。 RoutingService は、一方向、要求/応答、双方向メッセージングなど、さまざまなメッセージング パターンを使用して、WCF でサポートされているプロトコル経由のルーティング メッセージを処理できます。 RoutingService クラスの定義を次に示します。
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any,
InstanceContextMode = InstanceContextMode.PerSession、
UseSynchronizationContext = false、 ValidateMustUnderstand = false)
AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public sealed クラス RoutingService : // コントラクトを使用すると、さまざまな通信パターンが許可されます
ISimplexDatagramRouter、ISimplexSessionRouter、IRequestReplyRouter、
IDuplexSessionRouter、IDisposable
{
... // 実装を省略しました
}
ご覧のように、RoutingService クラスは、複数のメッセージング パターンをサポートするために、複数のサービス コントラクトから派生します。 各サービス コントラクトでは、必要に応じてセッション ベースの通信のサポートなど、異なるメッセージング パターンのサポートが提供されます。
RoutingService の全体的な目的は、コンシューマーから受信メッセージを受信し、それらを適切なダウンストリーム サービスに "ルーティング" することです。 RouterService は、一連のメッセージ フィルターに対して各受信メッセージを評価することによって、使用するターゲット サービスを決定します。 そのため、開発者は、通常は構成ファイルでメッセージ フィルターを定義することでルーティング動作を制御します。 ターゲット サービスは RouterService と同じマシン上に存在する可能性がありますが、そうする必要はありません。また、ネットワーク全体に分散することもでき、さまざまなプロトコルが必要になる場合があります。
RoutingService のホスト
RoutingService は、他の WCF サービスと同様に、アプリケーションでホストできます。 ServiceHost インスタンスを作成し、サービスの種類に RoutingService を指定するだけです。 ServiceHost インスタンスで Open を呼び出すと、次に示すように、RoutingService でメッセージを "ルーティング" する準備が整います。
using System;
System.ServiceModel を使用する。
System.ServiceModel.Routing を使用する。
public static void Main()
{
RoutingService 型の ServiceHost を作成します。
using (ServiceHost serviceHost =
new ServiceHost(typeof(RoutingService)))
{
試す
{
serviceHost.Open();
Console.WriteLine("The Routing Service is now running.");
Console.WriteLine("Enter> キーを押して<ルーターを終了します。);
サービスにアクセスできるようになりました。
Console.ReadLine();
serviceHost.Close();
}
catch (CommunicationException)
{
serviceHost.Abort();
}
}
}
また、他のサービスと同様に RoutingService を構成し、そこでルーティング フィルターを定義します。 まず、1 つ以上のエンドポイントを使用して構成する必要があります。 ルーティング エンドポイントを定義する場合は、WCF バインディングと、上記の RoutingService によって実装されたルーティング サービス コントラクトの 1 つ (ISimplexDatagramRouter、IRequestReplyRouter など) を選択します。 複数のメッセージング パターンまたは WCF バインドをサポートする場合は、RoutingService で複数のエンドポイントを公開できます。
次の例は、4 つのルーティング エンドポイントを使用して RoutingService を構成する方法を示しています。2 つは BasicHttpBinding (一方向と要求応答) を使用し、2 つは WSHttpBinding (一方向と要求応答) を使用します。 他の WCF サービスを構成するのと同じように注意してください。
<構成>
<system.serviceModel>
<services>
<--ルーティング サービス -->
<service behaviorConfiguration="routingData"
name="System.ServiceModel.Routing.RoutingService">
<host>
<baseAddresses>
<add baseAddress="https://localhost:8000/routingservice/router"/>
</baseAddresses>
</ホスト>
<!--
ルーターがリッスンするエンドポイントを定義して構成し、
使用する契約。 ルーターによって提供されるコントラクトは次のとおりです。
ISimplexDatagramRouter、ISimplexSessionRouter、IRequestReplyRouter、および
IDuplexSessionRouter。
-->
<endpoint address="oneway-basic"
binding="basicHttpBinding"
name="onewayEndpointBasic"
contract="System.ServiceModel.Routing.ISimplexDatagramRouter" />
<endpoint address="oneway-ws"
binding="wsHttpBinding"
name="onewayEndpointWS"
contract="System.ServiceModel.Routing.ISimplexDatagramRouter" />
<endpoint address="twoway-basic"
binding="basicHttpBinding"
name="reqReplyEndpointBasic"
contract="System.ServiceModel.Routing.IRequestReplyRouter" />
<endpoint address="twoway-ws"
binding="wsHttpBinding"
name="reqReplyEndpointWS"
contract="System.ServiceModel.Routing.IRequestReplyRouter" />
</service>
</サービス>
...
ISimplexDatagramRouter インターフェイスと IRequestReplyRouter インターフェイスは、ビジネス固有のサービス コントラクトと組み合わせて使用できる汎用の一方向および要求応答サービス コントラクト定義を定義します。 これらのインターフェイスが WCF でどのように定義されたかを次に示します。
[ServiceContract(Namespace="https://schemas.microsoft.com/netfx/2009/05/routing",
SessionMode = SessionMode.Allowed)]
パブリック インターフェイス ISimplexDatagramRouter
{
[OperationContract(AsyncPattern = true, IsOneWay = true, Action = "*")]
IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback,
オブジェクトの状態);
void EndProcessMessage(IAsyncResult result);
}
[ServiceContract(Namespace="https://schemas.microsoft.com/netfx/2009/05/routing",
SessionMode = SessionMode.Allowed)]
パブリック インターフェイス IRequestReplyRouter
{
[OperationContract(AsyncPattern = true, IsOneWay= false, Action = "*",
ReplyAction = "*")]
[GenericTransactionFlow(TransactionFlowOption.Allowed)]
IAsyncResult BeginProcessRequest(Message message, AsyncCallback callback,
オブジェクトの状態);
Message EndProcessRequest(IAsyncResult result);
}
上記のエンドポイント構成では、コンシューマーが使用するルーティング エンドポイントが公開されています。 クライアント アプリケーションは、クライアント コード内で使用するこれらのエンドポイントのいずれかを選択し、すべてのサービス呼び出しを RoutingService に直接送信します。 RoutingService は、これらのエンドポイントのいずれかを介してメッセージを受信すると、ルーティング メッセージ フィルターを評価して、メッセージを転送する場所を決定します。
メッセージ フィルターを使用した RoutingService の構成
RoutingService は、(WCF の他のすべてと同様に) コードまたは構成を使用して、メッセージ フィルターを使用して構成できます。 WCF 4 には、ルーティング メッセージ フィルターを管理するための RoutingBehavior が用意されています。 最初に RouterService で RoutingBehavior を有効にしてから、RoutingService のこの特定のインスタンスで使用するフィルター テーブルの名前を指定する必要があります。
<構成>
<system.serviceModel>
...
<behaviors>
<serviceBehaviors>
<behavior name="routingData">
<serviceMetadata httpGetEnabled="True"/>
<-- ルーティング動作を定義し、フィルター テーブル名を指定します -->
<routing filterTableName="filterTable1" />
</動作>
</serviceBehaviors>
</動作>
...
エンドポイントを使用して RoutingService を構成した前の例を見ると、behaviorConfiguration 属性を使用して "routingData" 動作がサービスに適用されていることがわかります。 次に、"filterTable1" という名前のフィルター テーブルを定義する必要があります。
ただし、フィルター テーブルを定義する前に、ルーティング先のターゲット サービスのエンドポイント定義が必要です。 これらのターゲット エンドポイントは WCF <クライアント> 構成セクション内で定義します。RoutingService は、メッセージをターゲット サービスに転送するときに基本的に "クライアント" であるためです。 次の例は、ルーティング先の 2 つのターゲット エンドポイントを定義する方法を示しています。
<構成>
...
<-- ルーターと通信するクライアント エンドポイントを定義します。
これらはルータがメッセージを送信する宛先です。 -->
<client>
<endpoint name="CalculatorService1"
address="https://localhost:8000/servicemodelsamples/calcservice1"
binding="wsHttpBinding" contract="*" />
<endpoint name="CalculatorService2"
address="https://localhost:8001/servicemodelsamples/calcservice2"
binding="wsHttpBinding" contract="*" />
</クライアント>
...
これで、実行時にルーティング ロジックを決定する実際のフィルター テーブルを定義できます。 filterTables> 要素内でフィルター テーブル エントリを<定義します。 filterTable> 内の<各エントリは、ルーティング "フィルター" とターゲット エンドポイントの間のマッピングを定義します。 filters> 要素内で<使用する "フィルター" を定義します。各<フィルター> エントリは、フィルター固有のデータ (アクション値、XPath 式など) と共に使用するフィルターの種類を指定します。
次の例では、CalculatorService1 エンドポイントにマップされる 1 つのフィルターを使用してフィルター テーブルを構成する方法を示します。 この場合、"MatchAll" フィルターはすべての受信メッセージと一致します。
<構成>
...
<--ルーティング セクション -->
<routing>
<-- ルーターで使用するフィルターを定義します。 -->
<filters>
<filter name="MatchAllFilter1" filterType="MatchAll" />
</フィルター>
<-- matchAll フィルターを含むフィルター テーブルを定義する -->
<filterTables>
<filterTable name="filterTable1">
<--以前に定義したクライアント エンドポイントにフィルターをマップします。
このフィルターに一致するメッセージは、この宛先に送信されます。 -->
<add filterName="MatchAllFilter1" endpointName="CalculatorService1" />
</filterTable>
</filterTables>
</ルーティング>
</system.serviceModel>
</構成>
ルーティング サービス ホスト アプリケーション、CalculatorService1 ホスト アプリケーション、およびルーター エンドポイントのいずれかにメッセージを送信するように設計されたクライアントを実行することで、ルーティングが正しく機能することを確認できます。 クライアントを実行すると、メッセージが中間 RoutingService によって "ルーティング" された後に CalculatorService 1 に到着することがわかります (図 14、図 15、図 16 を参照)。
図 14: RoutingService ホスト アプリケーション
図 15: RoutingService をターゲットとするクライアント https://localhost:8000/routingservice/router
図 16: ターゲット サービス (CalculatorService1)
メッセージ フィルターとコンテンツ ベースのルーティング
WCF には、受信メッセージの内容を検査するためにルーティング メッセージ フィルターと組み合わせて使用できる組み込みの MessageFilter クラスがいくつか用意されています。
たとえば、WCF には、特定のWS-Addressingの "action" 値を照合できる ActionMessageFilter が用意されています。 WCF には、特定のエンドポイントの詳細を照合できる EndpointAddressMessageFilter、EndpointNameMessageFilter、PrefixEndpointAddressMessageFilter も用意されています。 最も柔軟なものの 1 つは XPathMessageFilter です。これにより、受信メッセージに対して XPath 式を評価できます。 これらのフィルターはすべて、ソリューション内でコンテンツ ベースのルーティングを実行できます。
これらの組み込みの MessageFilter 型に加えて、WCF 4 では、RoutingService の主要な拡張ポイントの 1 つであるカスタム メッセージ フィルターを定義することもできます。
アクション値に基づいてコンテンツ ベースのルーティングを実行する例を見てみましょう。 CalculatorService 操作の半分を CalculatorService1 にルーティングし、残りの半分を CalculatorService2 にルーティングするとします。 これを実現するには、さまざまな CalculatorService アクション値ごとにフィルターを定義し、それらの半分を次に示すように各ターゲット サービス エンドポイントにマッピングします。
<構成>
...
<--ルーティング セクション -->
<routing>
<-- ルーターで使用するフィルターを定義します。 -->
<filters>
<filter name="addFilter" filterType="Action"
filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Add"/>
<filter name="subFilter" filterType="Action"
filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Subtract"/>
<filter name="mulFilter" filterType="Action"
filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Multiply"/>
<filter name="divFilter" filterType="Action"
filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Divide"/>
</フィルター>
<filterTables>
<filterTable name="filterTable1">
<add filterName="addFilter" endpointName="CalculatorService1"/>
<add filterName="subFilter" endpointName="CalculatorService2"/>
<add filterName="mulFilter" endpointName="CalculatorService1"/>
<add filterName="divFilter" endpointName="CalculatorService2"/>
</filterTable>
</filterTables>
</ルーティング>
</system.serviceModel>
</構成>
次に、ソリューションを実行し、4 つの操作すべてを呼び出すクライアントを実行すると、操作の半分が各サービス コンソール ウィンドウに表示されます (図 17 と図 18 を参照)。
図 17: CalculatorService1 の出力
図 18: CalculatorService2 の出力
XPathMessageFilter を使用すると、さまざまな XPath 式を指定して受信メッセージに対して評価できるため、柔軟性がさらに向上します。 XPath 式は、SOAP ヘッダーや SOAP 本文を含む受信メッセージの任意の部分を評価できます。 これにより、コンテンツ ベースのメッセージ フィルターを構築する際に非常に柔軟に対応できます。 XPathMessageFilter の仕組みを理解するために、XPath 式を使用して最後の例を書き換える方法を次に示します。
<構成>
...
<--ルーティング セクション -->
<routing>
<-- ルーターで使用するフィルターを定義します。 -->
<filters>
<filter name="addFilter" filterType="XPath"
filterData="/s:Envelope/s:Header/wsa:Action =
'http://Microsoft.Samples.ServiceModel/ICalculator/Add'"/>
<filter name="subFilter" filterType="XPath"
filterData="/s:Envelope/s:Header/wsa:Action =
'http://Microsoft.Samples.ServiceModel/ICalculator/Subtract'"/>
<filter name="mulFilter" filterType="XPath"
filterData="/s:Envelope/s:Header/wsa:Action =
'http://Microsoft.Samples.ServiceModel/ICalculator/Multiply'"/>
<filter name="divFilter" filterType="XPath"
filterData="/s:Envelope/s:Header/wsa:Action =
'http://Microsoft.Samples.ServiceModel/ICalculator/Divide'"/>
</フィルター>
<namespaceTable>
<add prefix="s" namespace="http://www.w3.org/2003/05/soap-envelope" />
<add prefix="wsa" namespace="http://www.w3.org/2005/08/addressing" />
</namespaceTable>
<filterTables>
<filterTable name="filterTable1">
<add filterName="addFilter" endpointName="CalculatorService1"/>
<add filterName="subFilter" endpointName="CalculatorService2"/>
<add filterName="mulFilter" endpointName="CalculatorService1"/>
<add filterName="divFilter" endpointName="CalculatorService2"/>
</filterTable>
</filterTables>
</ルーティング>
</system.serviceModel>
</構成>
filterData 属性には、受信メッセージに対して評価される XPath 式が含まれていることに注意してください (式は、この例のアクション値を単にチェック)。 namespaceTable> 要素を使用して名前空間プレフィックス バインドのセットを定義した<方法にも注目してください。 これは、上記のように XPath 式内で名前空間プレフィックスを使用する場合に必要です。 この構成でソリューションを再実行すると、以前と同じ結果が生成されます (図 17 と図 18 を参照)。
カスタム SOAP ヘッダーに基づいて、または SOAP メッセージの本文内で見つかったコンテンツに基づいてメッセージをルーティングする必要がある場合は、この XPath フィルター手法を使用する必要があります。
プロトコル ブリッジ
前の例では、クライアントとルーターの間、およびルーターとターゲット サービスの間で通信するために、同じ WCF バインディング (WSHttpBinding) を使用していました。 RoutingService は、ほとんどの WCF バインディング間で通信をブリッジできます。 たとえば、クライアントが WSHttpBinding 経由でルーターと通信するようにルーターを構成した後、ルーターは NetTcpBinding または NetNamedPipeBinding を使用してダウンストリーム ターゲット サービスと通信します。
このシナリオを処理するように RoutingService を構成する方法を見てみましょう。 RoutingService エンドポイント構成は上記と同じままにします。これにより、コンシューマーは BasicHttpBinding または WSHttpBinding 経由で RoutingService と通信できます。 ただし、次に示すように、ターゲット サービスのクライアント エンドポイント定義を NetTcpBinding と NetNamedPipeBinding を使用するように変更します。
<構成>
...
<-- ルーターが通信するクライアント エンドポイントを定義します。
これらはルータがメッセージを送信する宛先です。 -->
<client>
<endpoint name="CalculatorService1"
address="net.tcp://localhost:8001/servicemodelsamples/calcservice1"
binding="netTcpBinding" contract="*" />
<endpoint name="CalculatorService2"
address="net.pipe://localhost/servicemodelsamples/calcservice2"
binding="netNamedPipeBinding" contract="*" />
</クライアント>
...
もちろん、互換性のある NetTcpBinding エンドポイントと NetNamedPipeBinding エンドポイントをそれぞれサポートするように CalculatorService1 アプリケーションと CalculatorService2 アプリケーションを更新する必要があります。 この構成により、コンシューマーは BasicHttpBinding/WSHttpBinding を使用して RoutingService と通信でき、メッセージのルーティング先のサービスに応じて、ルーターは NetTcpBinding または NetNamedPipeBinding を使用してターゲット サービスと通信します。
エラーハンドとフォールト トレランス
RoutingService には、ランタイム通信エラーに対処し、基本的なレベルのフォールト トレランスをサポートするための組み込みメカニズムも用意されています。 フィルター テーブルを定義するときに、最初のターゲット エンドポイントと通信するとエラーが発生した場合に RoutingService によって使用される代替エンドポイントのさまざまなリストを定義できます。 これにより、基本的に "バックアップ" エンドポイントの一覧を作成できます。
次の例は、フィルター テーブル エントリに関連付けることができる backupLists> 要素内の<バックアップ エンドポイントの一覧を定義する方法を示しています。
<構成>
...
<--ルーティング セクション -->
<routing>
... <!-- ルーターで使用するフィルターを定義します。 -->
<filterTables>
<filterTable name="filterTable1">
<add filterName="addFilter" endpointName="CalculatorService1"
alternateEndpoints="backupEndpoints"/>
<add filterName="subFilter" endpointName="CalculatorService1"
alternateEndpoints="backupEndpoints"/>
<add filterName="mulFilter" endpointName="CalculatorService1"
alternateEndpoints="backupEndpoints"/>
<add filterName="divFilter" endpointName="CalculatorService1"
alternateEndpoints="backupEndpoints"/>
</filterTable>
</filterTables>
<backupLists>
<backupList name="backupEndpoints">
<add endpointName="CalculatorService2"/>
</backupList>
</backupLists>
</ルーティング>
</system.serviceModel>
</構成>
CalculatorService2 は現在、CalculatorService1 で TimeoutException、CommunicationException、または派生例外の種類が発生した場合にのみ使用される "バックアップ" エンドポイントであるため、この例では CalculatorService1 に転送するようにすべてのフィルター テーブル エントリを構成しました。 たとえば、ソリューションをもう一度実行して CalculatorService1 を閉じ、クライアント プログラムを実行すると、すべてのメッセージが CalculatorService2 に表示されます。 このルーティング構成はすべてホスト アプリケーション コードで動的に実行できることに注意してください。
マルチキャスト ルーティングの動作
RoutingService では、特定の受信メッセージを "マルチキャスト" 方式で複数の宛先に自動的にルーティングすることもできます。 受信メッセージが、構成されたフィルター テーブル内の複数のフィルターと一致すると、RoutingService によって、"一致" フィルターに関連付けられている各ターゲット エンドポイントにメッセージが自動的にルーティングされます。
次の例は、同じワイルドカード フィルターで構成された 2 つのルーティング エントリを示しています。これは、すべての受信メッセージに一致します。
<構成>
...
<--ルーティング セクション -->
<routing>
<-- ルーターで使用するフィルターを定義します。 -->
<filters>
<filter name="wildcardFilter" filterType="MatchAll" />
</フィルター>
<filterTables>
<filterTable name="filterTable1">
<add filterName="wildcardFilter" endpointName="CalculatorService1"/>
<add filterName="wildcardFilter" endpointName="CalculatorService2"/>
<add filterName="wildcardFilter" endpointName="CalculatorService3"/>
</filterTable>
</filterTables>
</ルーティング>
</system.serviceModel>
</構成>
この構成を行うと、各受信 SOAP メッセージは、メッセージ内の内容に関係なく、すべてのターゲット エンドポイントに自動的にルーティングされます。
このマルチキャスト動作は、前のセクションで説明したプロトコル ブリッジングとエラー処理機能を構成します。 唯一の問題は、マルチキャストは一方向または双方向の通信に対してのみ機能しますが、要求と応答の通信には機能しません。基になるシステムは、発信要求と受信応答の間で 1 対 1 の比率を維持する必要があるためです。
REST サポートの強化
WCF 4 には、WCF を使用して RESTful サービスを構築するときに役立ついくつかの新機能が付属しています。 この一連の機能は、WCF WebHttp Services と呼ばれるようになりました。 これには、コンシューマーに対する RESTful サービス、簡略化された HTTP キャッシュ、メッセージ形式の選択、REST に優しい例外、ASP.NET ルーティング統合、いくつかの新しい Visual Studio プロジェクト テンプレートなどを説明する自動ヘルプ ページのサポートが含まれます。 ここでは、これらの機能をすべて詳しく説明するスペースはありませんが、残りの情報へのリンクと共に、以下のいくつかのお気に入りについて簡単に紹介します。
これらの機能の多くは、昨年 WCF REST Starter Kit によって最初に導入され、現在は公式フレームワークに組み込まれています。 今後、WCF REST Starter Kit の機能のフォロースーツが増える可能性があります。
自動ヘルプ ページ
WCF 4 で WebServiceHost クラスを使用すると、RESTful サービスは自動ヘルプ ページ機能の利点を自動的に利用します。 これは、WSDL メタデータとクライアント側のコード生成が不足しているため、REST を使用する場合に非常に必要な追加です。これにより、コンシューマーはサービスの使用を開始する方法を簡単に把握できます。そのため、通常は、この新機能を有効にすることをお勧めします。
WebServiceHost クラスを使用してサービスをホストすると、WebHttpBehavior を使用してサービスが自動的に構成され、WebHttpBinding (ベース HTTP アドレス) で構成された既定の HTTP エンドポイントが追加されます。 WCF 4 の時点で、WebHttpBehavior クラスには、ホスト内で新しいヘルプ ページを有効にするかどうかを制御する HelpEnabled プロパティが付属しています。 次の構成例は、特定の REST エンドポイントに対して自動ヘルプ ページ機能を有効にする方法を示しています。
<構成>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior name="HelpBehavior">
<webHttp helpEnabled="true" />
</動作>
</endpointBehaviors>
</動作>
<services>
<service name="CounterResource">
<endpoint behaviorConfiguration="HelpBehavior"
binding="webHttpBinding"
contract="CounterResource" />
</service>
</サービス>
</system.serviceModel>
</構成>
ヘルプ ページを表示するには、サービスのベース アドレスを参照し、URL の末尾に "help" を追加します (図 19 を参照)。
図 19: RESTFul サービスの自動ヘルプ ページ
ヘルプ ページには、[WebGet] または [WebInvoke] で注釈が付けられた各操作の人間が判読できる説明が表示され、それぞれに対して URI テンプレート、サポートされている HTTP 操作、およびサポートされているメッセージ形式、基本的にコンシューマーが知る必要があるすべての情報が記載されています (図 20 を参照)。 また、各操作に [Description] 属性を適用することで、よりわかりやすい説明を提供することもできます。
要求/応答ごとに、ヘルプ ページには XML スキーマと、コンシューマーがサービスとの統合に使用できる対応するサンプル XML インスタンスも用意されています。 コンシューマーは、スキーマを使用して適切なクライアント側のシリアル化可能な型を生成するか、サンプル XML ドキュメントを検査して、適切な XML 処理コードの記述方法を手動で判断できます。 どちらの方法も便利です。
図 20: 特定の操作の自動ヘルプ ページ
この新しいヘルプ ページ機能により、RESTful サービスの検出が自動的に可能になり、最終的に他のユーザーが簡単に使用できるようになります。 コンシューマーは、サービスの URI 設計、サポートされている HTTP 操作、および要求/応答形式を検出でき、説明は常に WCF コードと同期し続けます。これは、ASP.NET Web サービスでの動作と同様です。
HTTP キャッシュのサポート
REST の主な利点の 1 つは、HTTP キャッシュです。 ただし、その利点を実現するには、要求メッセージと応答メッセージのさまざまな HTTP キャッシュ ヘッダーを活用する必要があります。 これは、WebOperationContext インスタンスを介して要求/応答ヘッダーに手動でアクセスすることで、WCF サービス操作内で実現できますが、適切に行うのは簡単ではありません。
そのため、WCF 4 には、GET 操作に宣言的に適用できる [AspNetCacheProfile] 属性を使用してキャッシュを制御するためのより単純なモデルが付属しています。 この属性を使用すると、各操作の ASP.NET キャッシュ プロファイル名を指定できます。バックグラウンドには、基になるすべての HTTP キャッシュの詳細を処理するキャッシュ インスペクター (CachingParameterInspector) があります。
[AspNetCacheProfile] 実装は、標準の ASP.NET 出力キャッシュ メカニズムに基づいています。 [WebGet] 操作に [AspNetCacheProfile] 属性を適用する方法の例を次に示します。
...
[AspNetCacheProfile("CacheFor60Seconds")]
[WebGet(UriTemplate=XmlItemTemplate)]
[OperationContract]
public Counter GetItemInXml()
{
return HandleGet();
}
...
これを行うには、web.config ファイル内に "CacheFor60Seconds" という名前の ASP.NET 出力キャッシュ プロファイルを定義する必要があります。 これを行う方法を次のweb.configに示します。
<構成>
<system.web>
<キャッシュ>
<outputCacheSettings>
<outputCacheProfiles>
<add name="CacheFor60Seconds" duration="60" varyByParam="format" />
</outputCacheProfiles>
</outputCacheSettings>
</キャッシュ>
</System.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
</構成>
ASP.NET キャッシュ プロファイルが出力を 60 秒間キャッシュするように設定され、"format" クエリ文字列変数によってキャッシュを変更するように構成されていることに注目してください。 問題のサービスは XML と JSON の両方をサポートしているため、これは重要です。これは、書式変数 (例: "?format=json") を使用して制御します。 サービスは、XML 応答と JSON 応答を相互に独立してキャッシュする必要があります。
この構成ファイルは、出力キャッシュなどのさまざまな ASP.NET 機能を利用する場合に必要な ASP.NET 互換モードを有効にする方法も示しています。
[AspNetCacheProfile] 属性を使用すると、HTTP キャッシュ ヘッダーを直接操作しなくても、HTTP キャッシュを利用しやすくなります。 基になる WCF の動作では、応答に HTTP Cache-Control、Date、Expires、Vary HTTP ヘッダーが挿入されます。クライアントは、 を利用して、今後のラウンド トリップに関する適切なキャッシュ セマンティクスを決定することもできます。
メッセージ形式の選択
図 19 を振り返ると、CounterResource サービスでは、GET、POST、PUT 操作の XML 形式と JSON 形式の両方がサポートされていることがわかります。 これは、WCF 3.5 以降、[WebGet] 属性と [WebInvoke] 属性で見つかった RequestFormat プロパティと ResponseFormat プロパティを介して可能です。
CounterResource サービスでこれを実現するには、次に示すように、バージョンごとに個別の操作コントラクト (XML バージョン用と JSON バージョン用) を定義しました。
...
[WebGet(UriTemplate="")]
[OperationContract]
public Counter GetItemInXml()
{
return HandleGet();
}
[WebGet(UriTemplate = "?format=json", ResponseFormat=WebMessageFormat.Json)]
[OperationContract]
public Counter GetItemInJson()
{
return HandleGet();
}
...
これは残念ながら、XML 形式と JSON 形式の両方をサポートする場合は、すべての論理操作に対して 2 つの操作コントラクトが必要であることを意味します。 CounterResource サービスの場合、GET、POST、PUT 操作の XML と JSON の両方をサポートする 6 つの操作コントラクトが必要でした。
WCF 4 では、HTTP "Accept" ヘッダーに基づく自動書式選択のサポートを提供することで、このシナリオをはるかに簡単に処理できます。これは、より適切な方法です。 このしくみについて説明します。
まず、論理操作ごとに 1 つの操作コントラクトのみが必要です。
[WebGet(UriTemplate="")]
[OperationContract]
public Counter GetItem()
{
return HandleGet();
}
次に、次に示すように、標準 WebHttpEndpoint での自動書式選択を行います。
<構成>
<system.serviceModel>
<standardEndpoints>
<webHttpEndpoint>
<--"" 標準エンドポイントは、Web エンドポイントの自動作成に使用されます。 -->
<standardEndpoint name="" helpEnabled="true"
automaticFormatSelectionEnabled="true"/>
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
</構成>
これで、サービスは XML または JSON メッセージを処理して返すようになりました。 要求メッセージで見つかった HTTP Accept ヘッダーを最初に調べることで、どの形式を使用するかを確認します。 それでも問題が解決しない場合は、要求メッセージと同じメッセージ形式が使用されます。XML または JSON であると仮定すると、それ以外の場合は特定の操作に既定の形式が使用されます。
HTTP Content-Type ヘッダーと Accept ヘッダーを使用して使用する形式を決定するのは、クライアント次第です。 Content-Type ヘッダーは要求メッセージ内の形式を指定します。Accept ヘッダーは、クライアントがサービスから "受け入れる" 形式を示します。 たとえば、クライアントがサービスから JSON を受信する場合は、要求で次の HTTP Accept ヘッダーを指定する必要があります。
Accept: application/json
これは、任意の HTTP クライアント プログラミング モデルで簡単に実行でき、Fiddler などのツールを使用して簡単に実行することもできます。 図 21 は、Fiddler を使用して、新しく改善されたサービスから JSON を取得する方法を示しています。
図 21: HTTP Accept ヘッダーを使用して JSON を取得する
WCF 4 には、実行時にメッセージ形式を簡単に明示的に指定できる新しい API も用意されています。 次のコードは、最初に "format" クエリ文字列パラメーターを検索し、それに応じて応答形式を明示的に設定するコードを記述することで、GetItem 操作を拡張する方法を示しています。 "format" パラメーターが見つからない場合は、以前のように Accept ヘッダーに依存するだけです。
[WebGet(UriTemplate="")]
[OperationContract]
public Counter GetItem()
{
書式指定クエリ文字列パラメーターが指定されている場合は、
応答形式をに設定します。 そのようなものがない場合
クエリ文字列パラメーターが存在する場合、Accept ヘッダーが使用されます
string formatQueryStringValue =
WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters[
"format"];
if (!string.IsNullOrEmpty(formatQueryStringValue))
{
if (formatQueryStringValue.Equals("xml",
System.StringComparison.OrdinalIgnoreCase))
{
WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml;
}
else if (formatQueryStringValue.Equals("json",
System.StringComparison.OrdinalIgnoreCase))
{
WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;
}
else
{
新しい WebFaultException<string>(string.Format("Unsupported format '{0}'",
formatQueryStringValue), HttpStatusCode.BadRequest);
}
}
return HandleGet();
}
最終的に、これらの新機能により、WCF 3.5 で行ったように、メッセージ形式の種類を [WebGet] および [WebInvoke] 操作コントラクトにハードコーディングする必要がなくなります。
RESTful エラー処理
RESTful サービスは SOAP を使用しないため、標準の SOAP 障害メカニズムを自由に使用できなくなり、.NET 例外と SOAP エラー メッセージの間で自動的にマップできるようになります。 WCF 3.5 で REST サービスを構築する場合、クライアントに返される HTTP エラー メッセージをカスタマイズする場合は常に、HTTP 応答メッセージを手動で作成する必要がありました。
WCF 4 では、WebFaultException<T> という新しいクラスが見つかります。これにより、"Web エラー" (HTTP エラーなど) をコンシューマーに簡単に送信できます。 WCF の FaultException<T> とよく似ていますが、HTTP 状態コードと詳細の種類を指定して詳細を指定できます。
次の例は、ユーザーがサポートされていない形式の種類を指定したときに HTTP 400 (Bad Request) エラーを返す方法を示しています。詳細型には文字列を使用しています。
if (!string.IsNullOrEmpty(format))
{
if (format.Equals("xml", System.StringComparison.OrdinalIgnoreCase))
{
WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml;
}
else if (format.Equals("json", System.StringComparison.OrdinalIgnoreCase))
{
WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;
}
else
{
新しい WebFaultException<string>(string.Format("Unsupported format '{0}'",
format)、HttpStatusCode.BadRequest);
}
}
この新機能により、SOAP ベースのサービスで通常と同じように例外をスローするだけで、標準の HTTP エラー メッセージを返す方がはるかに自然になります。
WCF と ASP.NET ルートの統合
WCF 4 と ASP.NET 4 の両方で見られる URL ベースのルーティング機能には、多くの類似点があります。 どちらも同じことを行うことができます。基本的に、URL テンプレートをクラスのメソッドにマップします。 ただし、2 つのモデルには大きな違いが 1 つあります。
WCF 4 アプローチでは、開発時にクラス定義に適用される [WebGet] 属性と [WebInvoke] 属性を使用して、URL テンプレートのデザインを 1 つのクラスに関連付けます。 サービスが時間の経過と共に成長し、進化するにつれて、小さなチャンクに分解できない大きなモノリシック設計につながる可能性があります。 一方、ASP.NET 4 のアプローチでは、ルーティング ロジックをターゲット クラス定義から切り離し、必要に応じて多数のクラス定義にわたってサービス ルートをマップできます。
WCF 4 では、ASP.NET ルーティング エンジンを WCF 4 サービスと統合できるようになりました。これにより、WCF サービスの上に ASP.NET ルーティング モデルを利用できます。
これを実現するには、Global.asax RegisterRoutes メソッドで、ASP.NET ルートを WCF サービス クラスにマップできる新しい ServiceRoute クラスを利用します。
private void RegisterRoutes()
{
WebServiceHostFactory ファクトリ = 新しい WebServiceHostFactory();
RouteTable.Routes.Add(new ServiceRoute("Bookmarks", factory,
typeof(BookmarkService)));
RouteTable.Routes.Add(new ServiceRoute("Users", factory,
typeof(UserService)));
}
RouteTable.Routes.Add を 2 回呼び出して、2 つの異なる WCF サービス クラスの新しいルートを追加しています。 最初のルートは "/Bookmarks" を BookmarkService クラスにマップし、2 番目のルートは "/Users" を UserService クラスにマップします。 WebServiceHostFactory を使用するように両方のルートがどのように構成されているかに注目してください。
ここで、WCF サービス クラス定義で [WebGet] 属性と [WebInvoke] 属性を使用すると、相対パスが使用され、ここで指定した ASP.NET ルートに対する相対パスになります。
REST プロジェクト テンプレート
Visual Studio 2010 の端正な機能の 1 つは拡張機能マネージャーであり、ツール |拡張機能マネージャー。 拡張機能マネージャーを使用すると、Microsoft や他のサード パーティは、新しいプロジェクト テンプレート、コントロール、ツールを、ボタンをクリックするだけで Visual Studio 2010 エクスペリエンスに統合できます。 Microsoft 製品チームの場合、RTM の後に発送し、Microsoft によって提供される公式の拡張機能を作成できるため、これは優れた機能です。
拡張機能マネージャーを起動して [テンプレート] ノードを展開すると、"WCF" という名前の子ノードが見つかります。 [WCF] をクリックすると、4 つの新しい WCF REST サービス テンプレートが表示されます。図 22 に示すように、.NET バージョン (3.5 と 4.0) ごとに 1 つ、言語ごとに 1 つ (C# と VB.NET) が表示されます。
図 22: 拡張機能マネージャーの新しい WCF REST プロジェクト テンプレート
これらの新しいプロジェクト テンプレートを選択し、ローカルの Visual Studio 2010 インストールにダウンロードして、他のプロジェクトの種類と同様に使用できます。 新しい REST プロジェクトの種類は、Visual C# |Web |WCF REST サービス アプリケーション (C# バージョンをインストールした場合)。
これを使用して新しいプロジェクトを作成すると、生成される WCF REST サービス アプリケーションで、このセクション全体で強調表示した新しい WCF 4 機能の大部分が使用されていることがわかります。
詳細情報
ここで説明した内容に加えて、WCF 4 には、カスタム メッセージ形式 (XML や JSON ではなく) の処理、新しい T4 機能を使用したテンプレート ベースの "ビュー" の返し、条件付き GET と ETag サポートの実装、オプティミスティック コンカレンシーの実装、送信リンクの生成などを簡略化する、より高度な REST 機能と新しい WCF API 拡張機能が用意されています。
ここで取り上げるスペースがなかった機能を含む、これらすべての新しい WCF 4 機能の詳細については、.NET エンドポイント ブログを参照し、「.NET 4 での WCF WebHttp Services の導入」のエントリを参照してください。 チームは、各新機能を一度に 1 つずつ説明する完全な 12 部のブログ シリーズと、サンプル コードとステップ バイ ステップの手順を多数提供しています。
ワークフロー サービス
.NET 4 で最も注目を集めた機能領域の 1 つは、"ワークフロー サービス" の機能です。 Microsoft は、さまざまなアプリケーションを構築するための豊富な宣言型プログラミング モデルを提供するために、WCF と WF の統合の改善に多大な投資を行ってきました。
ワークフロー サービスについて
WF では、ロジックを記述するユーザーの抽象化レベルを上げる宣言型プログラミング モデルが提供されます。 WF が最終的に提供するのは、ビジネス ドメイン アクティビティの独自のライブラリを定義することで、独自の言語を記述するためのフレームワークです。 その後、これらのアクティビティをプログラムに作成するためのビジュアル デザイナーと、それらのプログラムの実行を管理する方法を認識するランタイムが提供されます。
WF は、別のシステムからのメッセージの受信など、さまざまな種類の外部イベントが発生するのを待機する必要がある、実行時間の長いアプリケーションを実装するための特に優れたモデルを提供します。 永続化モデルを使用すると、プログラムを実際に実行している場合にのみメモリ内に保持することで、システム リソースを効率的に使用できます。 プログラムが外部イベントの発生を待機している場合は、データベースに永続化して、使用していたシステム リソースを解放できます。
図 23: ワークフロー サービス
WF が他の開発フレームワークと異なるのは、これらの機能を提供しながら、シーケンシャル フロー制御プログラミング ロジックを使用してプログラミングできるようにすることです。これは、通常、開発者がコードを読み書きして理解しやすくなります。
本質的に実行時間の長い WCF サービスを構築している場合、または先ほど説明した他の利点の一部を利用できる場合は、WF ワークフローを使用して WCF サービスを実装できます。 また、WF を使用して、他の外部サービスを使用するロジックを調整できます。
図 23 は、これらの概念を示しています。
これは .NET 3.5 以降可能でしたが、.NET 4 は開発者エクスペリエンスを向上させ、.NET 3.5 で不足していた必要な機能の一部を提供する上で大きな進歩を遂げました。
WCF と WF の世界を組み合わせることで、両方の世界を最大限に利用できます。 宣言型プログラミング モデル、WF デザイナーによる開発者向けのエクスペリエンス、実行時間の長いサービスを管理するための強力なランタイム、WCF によって提供される豊富な通信の柔軟性が得られます。
最初のワークフロー サービスの構築
新しいワークフロー サービス開発者エクスペリエンスを感じさせるために、.NET 4 と新しい Visual Studio 2010 デザイナーを使用してビルドする完全な例について説明します。
Visual Studio 2010 を開き、[ ファイル |新しいプロジェクトでは、WCF テンプレートの下に新しいワークフロー プロジェクトがあります。これは "WCF Workflow Service Application" と呼ばれます。 このプロジェクト テンプレートを選択し、"HelloWorldWorkflowService" という名前を付けて、新しいプロジェクトを作成します。
図 24: Visual Studio 2010 Workflow Services プロジェクト テンプレート
作成されると、新しいプロジェクトには、宣言型ワークフロー サービス定義を含む Service1.xamlx ファイルと、サービス構成を含むWeb.config ファイルという 2 つのファイルが含まれます。
.NET 4 の新しいワークフロー サービス モデルに関する最も説得力のある点の 1 つは、サービス定義全体を XAML で定義できることです。 新しいプロジェクトでは、Service1.xamlx ファイルにサービス定義が含まれており、実装は単に XAML ベースのワークフローです。 Web.config ファイルには WCF サービス構成が含まれています。ここでは、ワークフロー サービスのエンドポイントと動作を定義します。
図 25 は、Service1.xamlx ファイルの Visual Studio 2010 デザイナーの外観を示しています。 これは単なる標準ワークフロー デザイナーであることに注意してください。この特定の場合にのみ、設計するワークフローは WCF サービスの実装として機能します。 このワークフロー定義を WCF と統合する鍵となるのは、新しい WorkflowServiceHost と WCF の "メッセージング" アクティビティのセットです (図 25 のツールボックスを参照)。
図 25: Visual Studio 2010 でのワークフロー サービスの設計
このプロジェクト テンプレートで提供されるスケルトン ワークフロー サービスには、Receive アクティビティの後に Send アクティビティが含まれています。 Receive アクティビティに OperationName プロパティが含まれており、現在は "GetData" に設定されていることに注意してください。 また、受信メッセージを Sequence アクティビティ内で定義されたローカル変数にバインドするための Content プロパティもあります。この場合、変数は "data" と呼ばれ、Int32 型です (図 25 のワークフロー デザイン サービスの下にある変数ウィンドウを参照)。
Receive アクティビティは、サービスをアクティブ化するように構成されています。つまり、受信メッセージでワークフローの新しいインスタンスが作成される可能性があります。 図 25 の右側のプロパティ ウィンドウ内で CanCreateInstance プロパティがオンになっていることに注意してください。
このワークフロー サービスを少しカスタマイズしてみましょう。 まず、サービス ファイル名を Service1.xamlx から HelloWorld.xamlx に変更します。 次に、適切なウィンドウでサービスの名前を "HelloWorldService" に変更します。 次に、Receive アクティビティの OperationName プロパティを "SayHello" に変更します。 最後に、シーケンス内で String 型の "personName" という名前の新しい変数を定義します。
次に、図 26 に示すように、Receive アクティビティの Content プロパティを "personName" 変数にバインドします。 次に、Send アクティビティの Content プロパティを "hello {0}!" の形式の文字列にバインドします。 personName 変数をプレースホルダーに挿入する。 次に、結果の Service1.xamlx ファイルを保存します。
図 26: Receive アクティビティの Content プロパティの定義
この時点で、HelloWorld.xamlx ファイルを開き、その内容を調べます。 これを行うには、ソリューション エクスプローラーでファイルを右クリックし、[ファイルを開く]を選択します。 その後に "XML エディター" が続きます。 これにより、サービスの生の XAML 定義を確認できます。 XAML 定義は完全なサービス実装を表す点に注意してください。 C# コードはまったくありません。
このサンプルでは、既定の HTTP エンドポイントに依存し、WCF 構成を必要としないように、サービス メタデータを自動的に有効にする標準のサービス動作があることを前提としています。
これで、XAML ベースのワークフロー サービスをテストする準備ができました。 これは、Visual Studio 2010 で F5 キーを押すのと同じくらい簡単です。 F5 キーを押すと、ワークフロー サービスが ASP.NET 開発サーバーに読み込まれ、WCF テスト クライアントが表示されます。 WCF テスト クライアントは、ワークフロー サービスに自動的に接続し、WSDL メタデータをダウンロードして、ワークフロー サービス ロジックをテストできるようにします (図 27 を参照)。
図 27: ワークフロー サービスのテスト
これは、ワークフロー サービス インフラストラクチャが、ワークフロー定義内で使用される送受信アクティビティと、送受信するメッセージの種類を調べることで、サービスの WSDL 定義を動的に生成できることを示しています。
これで、.NET 4 で最初の宣言型ワークフロー サービスを構築する簡単なチュートリアルが完了します。 サービス実装は XAML で完全に定義されており、送受信アクティビティを使用してワークフロー内のメッセージングの相互作用をモデル化することを確認しました。 また、.NET 4 には .xamlx ファイルのホスティング サポートが付属しているため、追加の .svc ファイルは不要です。 これらの各領域の詳細については、次のセクションで引き続き詳しく説明します。
ワークフロー サービスのホスティング
.NET 4 には、ワークフロー サービス用の新しく改良されたホスティング インフラストラクチャが付属しています。 ワークフロー サービスは、IIS/WAS または WorkflowServiceHost を使用して独自のアプリケーションでホストできます。 .NET 4 ホスティング インフラストラクチャでは、実行時間の長いワークフロー インスタンスを管理したり、複数のサービス インスタンスが同時に実行されている場合のメッセージの関連付けに必要な要素を提供します。 .NET 4 には、ワークフロー インスタンスをリモートで管理するための標準ワークフロー コントロール エンドポイントも用意されています。
IIS/ASP.NET でのホスティング
前のセクションで説明した簡単な HelloWorldWorkflowService の例では、IIS/ASP.NET でワークフロー サービスをホストする方法を示しました。 ASP.NET 開発サーバーを使用してサービスをテストしましたが、ASP.NET 4 アプリケーション プールを使用して IIS 内で同じように動作していました。 .NET 4 では、バックグラウンドでの WorkflowServiceHost の作成と個々のワークフロー インスタンスのアクティブ化を処理する .xamlx 要求に必要なハンドラーがインストールされます。
最初の例では "ゼロ構成" アプローチを使用しましたが、他の WCF サービスと同様に、Web.config内でワークフロー サービスを構成できます。 ここで、使用する WCF エンドポイントと動作を構成します。 ワークフロー サービスでは、必要な数のエンドポイントを公開できますが、インスタンス固有の通信を管理する新しい "コンテキスト" バインディング (BasicHttpContextBinding、WSHttpContextBinding、NetTcpContextBinding など) のいずれかを使用することを検討する必要があります。
次の例は、2 つの HTTP エンドポイントを使用してワークフロー サービスを構成する方法を示しています。
<構成>
<system.serviceModel>
<services>
<service name="HelloWorldWorkflowService">
<endpoint binding="basicHttpContextBinding" contract="IHelloWorld"/>
<endpoint address="ws" binding="wsHttpContextBinding"
contract="IHelloWorld"/>
</service>
...
WCF の動作を使用してワークフロー サービスを構成することもできます。 次の例は、いくつかの標準的な WCF 動作を使用してこのワークフロー サービスを構成する方法を示しています。
<構成>
<system.serviceModel>
<services>
<service name="HelloWorldWorkflowService"
behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >
<endpoint binding="basicHttpContextBinding" contract="IHelloWorld"/>
<endpoint address="ws" binding="wsHttpContextBinding"
contract="IHelloWorld"/>
</service>
</サービス>
<behaviors>
<serviceBehaviors>
<behavior name="HelloWorldWorkflowService.Service1Behavior">
<serviceDebug includeExceptionDetailInFaults="False" />
<serviceMetadata httpGetEnabled="True"/>
</動作>
</serviceBehaviors>
...
これらの標準的な WCF 動作に加えて、.NET 4 には、ワークフロー サービスと組み合わせてワークフローの永続化、ワークフロー追跡、およびその他のワークフロー ランタイム動作を制御するための新しい WF 固有の動作がいくつか用意されています。 詳細については、.NET 4 SDK のサンプルを参照してください。
WorkflowServiceHost を使用したセルフホスティング
.NET 3.5 にはワークフロー サービスをホストするための WorkflowServiceHost クラスが付属していますが、.NET 4 の WF ランタイムとプログラミング モデルに対するすべての変更を考えると、再設計する必要がありました。 そのため、.NET 4 には、System.ServiceModel.Activities アセンブリにある新しい WorkflowServiceHost クラスが付属しています。
WorkflowServiceHost クラスを使用すると、コンソール アプリケーション、WPF アプリケーション、Windows サービスのいずれであっても、ワークフロー サービスを独自のアプリケーションで簡単にホストできます。 次のコード フラグメントは、独自のアプリケーション コード内で WorkflowServiceHost を使用する方法を示しています。
...
WorkflowServiceHost ホスト = 新しい WorkflowServiceHost("HelloWorld.xamlx",
new Uri("https://localhost:8080/helloworld"));
ホスト。AddDefaultEndpoints();
ホスト。Description.Behaviors.Add(
新しい ServiceMetadataBehavior { HttpGetEnabled = true });
ホスト。Open();
Console.WriteLine("Host is open");
Console.ReadLine();
...
ご覧のように、IIS/ASP.NET または独自のアプリケーションでワークフロー サービスをホストすることを選択した場合でも、WCF サービスと同じように簡単にホストできます。
WorkflowControlEndpoint
ワークフロー サービスをホストすると、公開されているエンドポイントの 1 つを介してメッセージをアクティブ化するときに、WF ランタイムの初期化と新しいワークフロー インスタンスのアクティブ化が行われます。 この基本的なホスティング機能に加えて、これらの実行中のワークフロー インスタンスの構成と実行をリモートで管理できることも重要です。 .NET 4 では、ワークフロー サービスで公開できる標準の WorkflowControlEndpoint を提供することで、これを簡単に実現できます。
次の例は、カスタム ホスティング シナリオで標準ワークフロー コントロール エンドポイントをサービスに追加する方法を示しています。
...
WorkflowServiceHost ホスト = 新しい WorkflowServiceHost("HelloWorld.xamlx",
new Uri("https://localhost:8080/helloworld"));
ホスト。AddDefaultEndpoints();
WorkflowControlEndpoint wce = 新しい WorkflowControlEndpoint(
新しい NetNamedPipeBinding()
new EndpointAddress("net.pipe://localhost/helloworld/WCE"));
ホスト。AddServiceEndpoint(wce);
ホスト。Open();
...
IIS/ASP.NET でホストしている場合は、次のように標準の WorkflowControlEndpoint を追加できます。
<構成>
<system.serviceModel>
<services>
<service name="HelloWorldWorkflowService"
behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >
<endpoint address="" binding="basicHttpContextBinding" contract="IHelloWorld"/>
<endpoint address="ws" binding="wsHttpContextBinding" contract="IHelloWorld"/>
<endpoint address="wce" binding="wsHttpBinding" kind="workflowControlEndpoint"/>
</service>
...
WorkflowControlEndpoint を使用すると、ワークフロー サービスをさまざまなホスティング環境内で管理できます。 このような環境の 1 つは、Windows Server AppFabric によって可能になり、今後のバージョンの Windows Server で使用できるようになります。
送受信アクティビティ
.NET 3.5 には、WCF を使用してメッセージを送受信するための 2 つのメッセージング アクティビティ (送受信) が含まれていますが、機能の面ではかなり制限されていました。 .NET 4 では、いくつかの追加機能 (関連付けなど) を使用して送受信アクティビティが強化され、さらにいくつかのメッセージング アクティビティ (SendReply と ReceiveReply) が追加され、要求/応答操作のモデリングが簡略化されます。
ワークフロー サービス内で送受信アクティビティを使用する場合は、基本的に WSDL 定義を介してクライアントに公開されるサービス コントラクトをモデル化するために使用します。 Receive アクティビティを使用する場合は、操作名を指定し、受信メッセージを .NET 型にマップします。 これまでは単純な文字列を使用してきましたが、複雑なユーザー定義データ コントラクトも使用できます。 HelloWorldWorkflowService を更新して、次のデータ コントラクト型を使用してみましょう。
[DataContract(Namespace="")]
パブリック クラス Person
{
[DataMember]
public string Id;
[DataMember]
public string FirstName;
[DataMember]
public string LastName;
}
このクラス定義を Web プロジェクトに追加し、HelloWorld.xamlx に戻ると、Person 型 (上記で定義されたデータ コントラクト) の "personMsg" という名前の新しい変数を定義できます。 次に、ReceiveRequest アクティビティと SendResponse アクティビティの両方を、"Content" プロパティを使用して personMsg 変数にマップできます。 これを行うには、各アクティビティを選択し、[コンテンツ] ボタンを押して [コンテンツ定義] ウィンドウを表示します。 次に、[メッセージ データ] テキスト ボックスに「personMsg」と入力し、[メッセージの種類] テキスト ボックスに「Person」と入力します。 両方のアクティビティに対してこれを行う必要があります。
Send/Receive アクティビティを使用すると、操作名、サービス コントラクト名、アクション、既知の型のコレクション、保護レベル、実行時に使用するシリアライザー (DataContractSerializer や XmlSerializer など) など、WCF サービスの他の側面を構成することもできます。 [送信] アクティビティでは、ターゲット エンドポイントの詳細も指定します。 送受信アクティビティが選択されている場合、これらの設定はすべてプロパティ ウィンドウを使用して構成できます。
これらの変更を行うと、HelloWorld.xamlx をもう一度テストして、SayHello 操作が Person 型のメッセージを受信して返すように定義されていることを確認できます。
Request-Reply操作の定義
要求/応答操作をモデル化しやすくするために、.NET 4 では、これらの種類の対話をモデル化するための新しいアクティビティがいくつか導入されています。 1 つは SendReply アクティビティであり、Receive アクティビティと組み合わせてサービス内に要求/応答操作を実装できます。 また、ワークフロー内で外部サービスを呼び出すときに Send アクティビティと組み合わせることができる ReceiveReply アクティビティもあります。
.NET 4 には、ReceiveAndSendReply と SendAndReceiveReply という高レベルのアクティビティがいくつか用意されています。これは Visual Studio 2010 ツールボックス内に表示されます。 これらのアクティビティは、それぞれ SendReply/ReceiveReply を使用して Receive/Send を作成し、使いやすくします。 ワークフロー デザイン画面にドラッグすると、Send アクティビティまたは Receive アクティビティとそれに続く適切な "返信" アクティビティが含まれるシーケンスに展開されます。
サービス参照の追加
外部サービスを使用するときにさらに簡単にするために、Visual Studio 2010 には、クライアント プロキシ クラス定義を生成する代わりに、一連のクライアント側アクティビティが生成される点を除き、期待どおりに動作する "サービス参照の追加" 機能も用意されています。 [サービス参照の追加] を選択し、WSDL 定義のアドレスを指定すると、Visual Studio によって WSDL がダウンロードされ、WSDL 定義で見つかった各操作のカスタム アクティビティが生成されます。
簡単な例を見てみましょう。 ワークフロー サービスから使用する CalculatorService と、Add、Subtract、Multiply、Divide の各操作があるとします。 図 28 に示すように、[サービス参照の追加] を選択し、CalculatorService WSDL 定義の場所を指定するだけです。
図 28: サービス参照の追加
[OK] を押してサービス参照を追加すると、Visual Studio によって WSDL 定義がダウンロードされ、ツールボックスに表示される 4 つのカスタム アクティビティが生成されます。 これで、ワークフロー内で使用して外部サービスを呼び出すのが簡単な Add、Subtract、Multiply、Divide アクティビティが作成されました。
Correlation
実行時間の長いワークフロー サービスで構成されるシステムを構築する場合、1 つのワークフロー サービスの多数のインスタンスが同時に実行され、同じイベントが発生するのを待機する (たとえば、続行する前に特定のメッセージが到着するのを待つなど) ことが一般的です。 このシナリオの課題は、受信メッセージを適切なワークフロー インスタンスと関連付ける方法が必要であるということです。 通常、正しいワークフロー インスタンスを特定する方法は、受信メッセージの内容を調べることです。
.NET 4 には、先ほど説明した送受信アクティビティと組み合わせて使用できる高度なコンテンツベースのメッセージ関連付け機能が付属しています。 この機能の実装は、.NET 4 のもう 1 つの新しい概念である "関連付けハンドル" と呼ばれるものを中心に展開されています。
関連付けの使用を開始するには、まず CorrelationHandle 型のワークフロー変数を定義する必要があります。 この変数は、2 つの異なるメッセージ (2 つの異なるメッセージング アクティビティによって処理される) からデータの一部を接続するためのランデブー ポイントと考えることができます。 Send アクティビティと Receive アクティビティの両方で、CorrelationHandle 変数を指定するための CorrelationsWith プロパティが提供されます。
複数の送受信アクティビティによって送信されるメッセージを関連付けるためには、関連付けに参加するすべてのアクティビティで同じ関連付けハンドルを指定する必要があります。 次に、各アクティビティで、その特定のアクティビティによって処理されるメッセージにマップされる関連付けキーを構成します (たとえば、あるメッセージの SSN 要素は、別のメッセージの CustomerId 要素と関連付けることができます)。 関連付けキーは、メッセージに対して評価される XPath 式を使用して定義します。
HelloWorldWorkflowService を拡張して、この動作の例を確認してみましょう。 現在、使用しているサンプルは Person メッセージを受け取り、クライアントに返します。 ワークフローの下部にある SendResponse アクティビティのすぐ下に、別の ReceiveAndSendReply アクティビティを追加してみましょう。 これにより、別の Receive を含む Sequence が追加され、その後に別の SendReply が追加されます。 Receive アクティビティに "Finish" という操作名を付けます。最後のあいさつ応答を作成するために使用する Finish メッセージで、クライアントにあいさつ文を提供するよう要求します。
つまり、クライアントは最初に SayHello を呼び出してフル ネームを指定し、新しいワークフロー サービス インスタンスを開始します。 その後、ワークフロー インスタンスは、クライアントが [完了] を呼び出してあいさつ文を提供するまで待機します (これには数分、数時間、または数日かかる可能性があり、その間はワークフローが保持される可能性があります)。 クライアントが [完了] を呼び出してあいさつ文を指定すると、ワークフローはあいさつ文と元の名前を使用してあいさつ文を作成し、それを返します。 このシナリオでは、Finish 操作が呼び出されるのを待機している複数の実行中のワークフロー インスタンスを簡単に作成できるため、Finish メッセージを前の SayHello メッセージと関連付ける必要があります。 この場合、"Finish" の Receive アクティビティを、"SayHello" アクティビティ (nameHandle) で指定したのと同じ関連付けハンドルに関連付ける必要があります。
次に、これら 2 つのアクティビティ間で関連付けるメッセージ コンテンツを見てみましょう。 この例では、次の 2 つのデータ コントラクト型を使用してメッセージをモデル化します。
[DataContract(Namespace="")]
パブリック クラス Person
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
[DataContract(Namespace = "")]
パブリック クラスの Greeting
{
[DataMember]
public string Salutation { get; set; }
[DataMember]
public string NameKey { get; set; }
}
"SayHello" の受信アクティビティは Person メッセージを使用するように構成され、"Finish" の Receive アクティビティは Greeting メッセージを使用するように構成されています。 LastName 値は常に一意であると想定し、関連付けの一意の値として使用できるようにします。 そのため、クライアントが "Finish" メッセージを送信するときは、前の "SayHello" メッセージで使用されたのと同じ LastName 値を指定する必要があります。
ここで、関連付けハンドルを構成してこれを設定する方法を見てみましょう。 "handle" という名前のシーケンス内で CorrelationHandle 変数を既に定義しています。 最初に行う必要があるのは、"SayHello" Receive アクティビティ内の関連付けハンドルを "初期化" することです。 そのため、"SayHello" Receive アクティビティを選択し、[CorrelationInitializers] テキスト ボックスの横にあるボタンを押します。
ここでは、ドロップダウン ボックスから [クエリ関連付け初期化子] を選択する必要があります。その後、クエリ フィールドの "LastName" プロパティを選択できます (図 29 に示すように、"sm:body()/xg0:Person/xg0:LastName" の XPath 式が生成されます)。
次に、"Finish" Receive アクティビティとが同じハンドルに関連付けられることを指定する必要があります。 [完了] 受信アクティビティを選択し、"CorrelatesOn" ボタンを押します。 次に、"CorrelatesWith" ハンドルに "handle" を指定し、クエリ フィールドに "NameKey" を選択します (図 30 を参照)。
図 29: "SayHello" の関連付けキーの定義
図 30: "完了" の関連付けキーの定義
つまり、最終的には、Person メッセージの LastName 要素は、2 つの個別の要求で Greeting メッセージの NameKey 要素と一致する必要があります。 これにより、ワークフロー インフラストラクチャは自動的にメッセージを関連付け、受信した "Finish" メッセージを正しいワークフロー インスタンスにルーティングできます ("LastName/NameKey" に基づく)。
最後の SendReply アクティビティは、元の "personMsg" と新しい "greetingMsg" からの情報を含む、次の書式設定された文字列を呼び出し元に返します。
String.Format("{0}{1}{2}!",
greetingMsg.Salutation, personMsg.FirstName, personMsg.LastName)
WCF テスト クライアントを使用して関連付け機能をテストし、異なる FirstName 値と LastName 値で SayHello を何度も呼び出して、複数のワークフロー インスタンスを開始します。 これを行った後、ワークフロー サービスのいくつかの実行中のインスタンスが必要です。 ここで、SayHello メッセージの 1 つで使用されているのと同じ LastName 値のいずれかを指定して Finish 操作を呼び出すと、クライアントに返される最終応答で使用される対応する FirstName 値が表示されます (図 31 を参照)。
これは、.NET 4 に付属する魅力的なワークフロー サービス機能である、実際のコンテンツ ベースの相関関係を示しています。 .NET 3.5 (チャネルまたはワークフロー インスタンス ID の使用など) で行った場合と同様に、チャネルとプロトコル レベルのデータに基づいて関連付けを実行することもできます。 コンテンツベースの関連付けは、同じことを行うためのより柔軟で洗練されたアプローチです。
図 31: コンテンツ ベースの関連付けの例をテストする
これにより、ワークフロー サービスの対象範囲が終了します。 このペーパーではワークフロー サービスの表面を傷つけることしかできませんでしたが、.NET 4 SDK のサンプルと、オンラインで見つかった増大する MSDN ドキュメントで追加情報を見つけることができます。 ご覧のように、WCF と WF 4 の組み合わせにより、宣言型、長時間実行、非同期のサービスを構築するためのまったく新しい開発モデルへの扉が開き、両方のフレームワークで提供する必要がある最高の機能を利用できます。
その他の高度な機能
この記事で説明した他のすべての機能に加えて、WCF 4 には、役に立つ高度な機能がいくつか用意されています。 これらの高度な機能には、DataContractResolver による型解決のサポートの強化、ReceiveContext を使用して競合するキュー コンシューマーを処理する機能、新しいバイト ストリーム エンコーダー、および高パフォーマンス ETW ベースのトレースが含まれます。
DataContractResolver を使用した型解決
WCF 3.x には、"既知の型" と呼ばれる型解決機能があります。 逆シリアル化中に、シリアライザーが宣言された型と同じ型ではないインスタンスを検出すると、宣言された "既知の型" の一覧を調べて、使用する型を特定します。 サービスの作成者は、[KnownType] 属性または [ServiceKnownType] 属性を使用して型/メソッドに注釈を付け、置換可能な一覧を定義できます。 この機能は、継承とポリモーフィズムをサポートするために一般的に使用されます。
残念ながら、WCF 3.x では、実行時にこの種類の動的型解決を実行するときに DataContractSerializer によって使用される型マッピング アルゴリズムを簡単にオーバーライドする方法は提供されません。 この問題に対処するために、WCF 4 には、独自のカスタム型解決アルゴリズムを実装するために派生できる抽象 DataContractResolver クラスが用意されています。 開始する方法を次に示します。
クラス MyDataContractResolver : DataContractResolver
{
アセンブリ アセンブリ。
public MyDataContractResolver(Assembly assembly)
{
this.assembly = assembly;
}
逆シリアル化時に使用されます
ユーザーが xsi:type 名を任意の種類にマップできるようにします
public override Type ResolveName(string typeName, string typeNamespace,
型 declaredType、DataContractResolver knownTypeResolver)
{
... // マッピングを実装する
}
シリアル化で使用されます
任意の型を新しい xsi:type 表現にマップします
public override bool TryResolveType(Type type, Type declaredType,
DataContractResolver knownTypeResolver,out XmlDictionaryString typeName,
out XmlDictionaryString typeNamespace)
{
... // マッピングを実装する
}
}
カスタム DataContractResolver を実装したら、次に示すように DataContractSerializer に指定できます。
DataContractSerializer dcs = new DataContractSerializer(
typeof(Object), null, int.MaxValue、false、true、null、
new MyDataContractResolver(assembly));
この DataContractSerializer インスタンスを使用してオブジェクトをシリアル化または逆シリアル化すると、カスタムの DataContractResolver が呼び出され、カスタム型解決が実行されます。
カスタム DataContractResolver をバックグラウンドで WCF ランタイムに挿入するには、DataContractSerializerOperationBehavior にプラグインし、既定の競合回避モジュールをオーバーライドする WCF コントラクト動作を記述する必要があります。 .NET 4 SDK には、コントラクトの動作と [KnownAssembly] というカスタム属性を使用してこれを実現する方法を示す完全な例が付属しています。
カスタム型解決は、DataContractSerializer の既定値をオーバーライドしたり、シリアル化に使用する型を正確に制御したり、既知の型を動的に管理したりする場合に便利です。
ReceiveContext を使用したキューメッセージの処理
WCF 3.x では、トランザクション キューを使用し、MSMQ トランザクションに WCF サービス操作を参加させることで、NetMsmqBinding を使用する場合に、メッセージの 1 回限りの配信を保証できます。 メッセージの処理中に例外がスローされると、WCF はメッセージをキューに返すことによってメッセージが失われていないことを確認します (構成によっては、元のキュー、有害なメッセージ キュー、または配信不能キューに返される可能性があります)。
この機能は重要ですが、一般的に発生する問題がいくつかあります。 1 つは、トランザクションがコストがかかり、キューで大量の読み取り/書き込みが生成され、オーバーヘッドと複雑さが増すことです。 もう 1 つの問題は、同じサービスが次回キューから引き出されるときにメッセージを確実に処理する方法がないことです (たとえば、特定のサービスがメッセージを "ロック" する方法はありません)。これは、特定のシナリオで行う必要がある保証です。
これらの問題に対処するために、WCF 4 では、キューに登録されたメッセージを処理するための ReceiveContext という新しい API が導入されています。 ReceiveContext を使用すると、サービスはキュー上のメッセージを "ピーク" して処理を開始し、問題が発生して例外がスローされた場合は、キューに残ります。 サービスではメッセージを "ロック" して、後で処理を再試行することもできます。 ReceiveContext には、メッセージを処理した後にメッセージを "完了" するためのメカニズムが用意されているため、キューから削除できます。
この方法では、メッセージがネットワーク経由でキューに読み取られ、書き直されなくなり、処理中に個々のメッセージが異なるサービス インスタンス間でバウンスしないため、いくつかの面で処理が簡略化されます。 簡単な例を見て、そのしくみを説明しましょう。
次の例は、ReceiveContext を使用してキューに到着するメッセージを処理する方法を示しています。
...
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
[ReceiveContextEnabled(ManualControl = true)]
public void CalculateProduct(int firstNumber, int secondNumber)
{
ReceiveContext receiveContext;
if (!ReceiveContext.TryGet(OperationContext.Current.IncomingMessageProperties,
out receiveContext))
{
Console.WriteLine("ReceiveContext not installed/found on this machine.");
return;
}
if ((firstNumber * secondNumber) % 2 == (receiveCount % 2))
{
receiveContext.Complete(TimeSpan.MaxValue);
Console.WriteLine("{0} x {1} = {2}", firstNumber, secondNumber,
firstNumber * secondNumber);
}
else
{
receiveContext.Abandon(TimeSpan.MaxValue);
Console.WriteLine("{0}&{1} not processed", firstNumber, secondNumber);
}
receiveCount++;
}
...
成功したパスを前提として、ReceiveContext.Complete を呼び出してメッセージの処理を完了し、基になるキューからメッセージが削除されます。 それ以外の場合は Abandon を呼び出します。これにより、今後の再試行のためにメッセージがキューに残されます。 .NET 4 SDK には、この新機能をさらに詳しく調べるために使用できる完全なサンプルが付属しています。
ByteStreamMessageEncodingBindingElement を使用したエンコードの合理化
一部のメッセージング シナリオでは、ラップや追加の処理を一切行わずにバイナリ データの "BLOB" を送信するだけです。 このシナリオを簡略化するために、WCF 4 には、これを行う新しい ByteStreamMessageEncodingBindingElement が付属しています。 残念ながら、.NET 4 にはこのエンコーダー用の新しいバインドが付属していないため、それを使用するにはカスタム バインドを作成する必要があります。
.NET 4 SDK には、カスタム バインド クラスを介して ByteStreamMessageEncodingBindingElement を使用するカスタム バインドを定義する方法を示す完全な例が付属しています。 新しいバインディング クラスを配置すると、バイト ストリーム エンコーダーはサービスで非常に簡単に使用できるようになります。
高パフォーマンス ETW ベースのトレース
WCF 4 では、トレースと診断フロントに対していくつかの機能強化も行っています。 WCF 4 では、トレースに ETW が使用されるようになりました。これにより、トレースのパフォーマンスが大幅に向上し、Windows Workflow Foundation、Windows Server AppFabric、Windows Server で見つかったさまざまな管理テクノロジなどの関連テクノロジとの統合が向上し、プラットフォームのモデルが向上します。
ETW を使用すると、イベント プロバイダーはセッションにイベントを書き込み、必要に応じてそれらのイベントをログに保持できます。 コンシューマーは、リアルタイムのセッション イベントをリッスンしたり、事後にログからそれらのイベントを読み取ったりできます。 ETW コントローラーは、セッションを有効または無効にし、プロバイダーをセッションに関連付けます。
.NET 4 SDK には、この新しいハイ パフォーマンス トレース アーキテクチャを WCF サービスと組み合わせて活用する方法を示す簡単な例が用意されています。
まとめ
WCF 4 には、今日の最も一般的な通信シナリオのいくつかに対応する、多数の機能強化と完全に新機能が用意されています。 まず第一に、WCF 4 は簡略化された構成モデルを使用しやすくなり、一般的な既定値のサポートが向上します。
さらに、WCF 4 では、ほとんどのエンタープライズ環境と大規模な SOA イニシアチブで一般的な要件であるサービスの検出とルーティングに対するファースト クラスのサポートが提供されています。これらの機能だけで、WCF は競合する多くのフレームワークとは別に設定されます。 WCF 4 では、REST ベースのサービス開発も簡略化され、現在の特定の問題点に対処する他のいくつかのより高度な WCF 機能も提供されています。
このすべてに加えて、WCF 4 では WF との高度な統合が提供され、宣言型ワークフロー サービスを開発するための新しいモデルが提供されます。 ワークフロー サービスを使用すると、WF プログラミング モデルと基になるランタイムの恩恵を受ける、実行時間の長い非同期サービスを開発できます。 また、新しい WCF ベースのアクティビティと Visual Studio 2010 内のデザイナー サポートにより、この新しいプログラミング モデルは、サービスを作成するためのファースト クラスのオプションになっています。
.NET 4 では、WCF と WF の世界が統合され、両方の世界が提供する最適なまとまりのあるプログラミング モデルが提供されています。 WF 4 の新機能の詳細については、「A Developer's Introduction to Windows Workflow Foundation in .NET 4」をチェック。
著者について
Aaron Skonnard は Pluralsight の共同創設者であり、講師主導の .NET 開発者コースとオンデマンドの .NET 開発者コースの両方を提供する Microsoft トレーニング プロバイダーです。 最近アーロンは、Pluralsight On-Demand の記録にほとんどの時間を費やしています。 クラウド コンピューティング、Windows Azure、WCF、REST に重点を置いたコース。 アーロンは、世界中のプロの開発者を書き、話し、教えることに長年費やしてきました。 と で彼にhttp://pluralsight.com/aaronhttp://twitter.com/skonnard連絡できます。