このタスクでは、WCF コントラクトを使用して、クライアントとホスト間の通信を有効にします。ホスト アプリケーションはクライアント上の 1 つの操作を呼び出します。この操作は、クライアント ワークフローを開始し、開始値でワークフローを初期化するようにデザインされています。
また、このタスクでは、新しいインターフェイスを使用して WCF コントラクトをもう 1 つ作成するのではなく、ワークフロー優先メソッドを使用して WCF コントラクトをプログラムで作成する方法についても説明します。
![]() |
---|
Visual Studio ワークフロー デザイナを使用してワークフロー サービスを作成または管理する場合、誤った検証エラーが発生することがあります。プロジェクトを正常に作成できる場合は、このような検証エラーを無視してください。 |
手順
ローカル ホスト通信のコントラクトを作成するには
メモ Visual Studio ワークフロー デザイナを使用してワークフロー サービスを作成または管理する場合、誤った検証エラーが発生することがあります。プロジェクトを正常にビルドできる場合は、このような検証エラーは無視してください。
WorkflowServiceTutorial ソリューションを開きます。
WorkflowServiceClient プロジェクト ノードで、このプロジェクトのワークフロー デザイナを開きます。
ReceiveActivity アクティビティをデザイナにドラッグし、最初の SendActivity アクティビティ上に配置して、ReceiveActivity アクティビティがワークフローで最初に実行されるようにします。
このアクティビティは、ローカル ホスト通信のコントラクトで定義した操作を実装します。
ReceiveActivity アクティビティを選択し、ServiceOperationInfo の [プロパティ] ペインで、省略記号をクリックして [操作の選択] ダイアログ ボックスを開きます。
ワークフロー優先の作成スタイルを使用して新しいコントラクトを定義しようとしているので、右上隅にある [コントラクトの追加] をクリックし、Contract1 を強調表示します。
[コントラクト名] ボックスで、コントラクトに ILocalHostContract という名前を付けます。
ILocalHostContract の下の最初の操作を強調表示し、この操作の名前を StartClientWorkflow に変更します。
[パラメータ] タブで、追加記号をクリックし、[方向] に入力を指定して initialValue という名前の Int32 型の新しいパラメータを追加し、[OK] をクリックします。
ReceiveActivity アクティビティを選択し、[プロパティ] ペインで initialValue をグローバル変数 inputValue にバインドします。
また、[プロパティ] ペインで、CanCreateInstance プロパティを [True] に設定します。
これで、ILocalHostContract という名前の新しいコントラクトがプログラムで定義されましたが、このコントラクトをワークフロー サービスとのやり取りに使用できるようにするには、さらに、ファイルをいくつか変更する必要があります。
WorkflowServiceClient プロジェクトの App.config ファイルを開きます。
次の構成コードを追加します。
<services> <service name="WorkflowServiceClient.ClientWorkflow" behaviorConfiguration="WorkflowServiceClient.ClientWorkflowBehavior"> <host> <baseAddresses> <add baseAddress="https://localhost:8090/ClientWorkflow" /> </baseAddresses> </host> <endpoint address="" binding="wsHttpContextBinding" contract="ILocalHostContract" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WorkflowServiceClient.ClientWorkflowBehavior" > <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> <serviceCredentials> <windowsAuthentication allowAnonymousLogons="false" includeWindowsGroups="true" /> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors>
これで、ローカル ホスト通信のコントラクトのエンドポイント アドレスを定義しました。このチュートリアル全体で使用してきたクライアントも、この新しいコントラクトを実装します。
ローカル ホスト通信を設定するには
Program.cs を開き、ファイルの先頭に次の using ステートメントを追加します。
using System.ServiceModel; using System.ServiceModel.Description;
Visual Basic ソリューションを作成した場合は、WorkflowServiceClient プロジェクト ノードを右クリックし、[プロパティ] をクリックします。[参照] タブをクリックし、[インポートされた名前空間] の下の、System.ServiceModel のチェック ボックスと System.ServiceModel.Description のチェック ボックスをオンにします。
今度は、ローカル ホスト通信を有効にしたり、ワークフロー サービスに対してクライアント ワークフローの操作呼び出しを実行したりするために、WorkflowServiceHost を使用するので、コンソール ホスト アプリケーションがワークフロー サービス クライアントと通信できるように Main メソッドを変更する必要があります。次のコードは、ローカル ホスト通信を容易にするために Main の実装をどのように変更する必要があるかを示しています。
Shared Sub Main() ' Create a WorkflowServiceHost object to listen for operation invocations. Using ConsoleHost As New WorkflowServiceHost(GetType(ClientWorkflow)) Dim waitHandle As New AutoResetEvent(False) ' Add ChannelManagerService to the list of services used ' by the WorkflowRuntime. Dim cms As New ChannelManagerService() ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.AddService(cms) AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowCompleted, AddressOf OnWorkflowCompleted AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowTerminated, AddressOf OnWorkflowTerminated AddHandler ConsoleHost.Closed, AddressOf OnConsoleClosed ' Call Open to start receiving messages. ConsoleHost.Open() ' After the client workflow is started, block until receiving waitHandle.Set is called ' so that the console application does not exit before the client workflow has completed ' and ConsoleHost.Close is called. waitHandle.WaitOne() End Using End Sub Shared Sub OnWorkflowCompleted(ByVal sender As Object, ByVal e As WorkflowCompletedEventArgs) Console.WriteLine("The client workflow has completed." + vbLf + "Press <Enter> to exit the client application.") Console.ReadLine() WaitHandle.Set() End Sub Shared Sub OnWorkflowTerminated(ByVal sender As Object, ByVal e As WorkflowTerminatedEventArgs) Console.WriteLine(e.Exception.Message) WaitHandle.Set() End Sub ' After the WorkflowServiceHost transitions to the closed state, allow the console ' application to exit by signaling to the AutoResetEvent object that it is okay to unblock ' the main thread. Shared Sub OnConsoleClosed(ByVal sender As Object, ByVal e As EventArgs) WaitHandle.Set() End Sub
static void Main(string[] args) { // Create a WorkflowServiceHost object to listen for operation invocations. using (WorkflowServiceHost ConsoleHost = new WorkflowServiceHost(typeof(ClientWorkflow))) { AutoResetEvent waitHandle = new AutoResetEvent(false); // Add ChannelManagerService to the list of services used // by the WorkflowRuntime. ChannelManagerService cms = new ChannelManagerService(); ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.AddService(cms); ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { Console.WriteLine("The client workflow has completed. \nPress <Enter> to exit the client application."); Console.ReadLine(); ConsoleHost.Close(); }; ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine(e.Exception.Message); waitHandle.Set(); }; // After the WorkflowServiceHost transitions to the closed state, allow the console // application to exit by signaling to the AutoResetEvent object that it is okay to unblock // the main thread. ConsoleHost.Closed += delegate(object sender, EventArgs e) { waitHandle.Set(); }; // Call Open to start receiving messages. ConsoleHost.Open(); // After the client workflow is started, block until receiving waitHandle.Set is called // so that the console application does not exit before the client workflow has completed // and ConsoleHost.Close is called. waitHandle.WaitOne(); } }
クライアント サービスをビルドして、実行します。
SvcUtil.exe を使用して、ローカル ホスト通信操作とのやり取りに必要なプロキシ コードと構成コードを生成します。
SvcUtil.exe の使用
SvcUtil.exe を使用するには、「ServiceModel Metadata Utility Tool」を参照してください。
プロキシ コードと構成ファイルを生成したら、次の手順に従ってそれらのファイルを WorkflowServiceClient プロジェクトに追加します。
- [ソリューション エクスプローラ] ペインに移動します。
- WorkflowServiceClient プロジェクト ノードを右クリックします。
- [追加] を強調表示し、[既存の項目] を選択します。
- SvcUtil.exe で構成ファイルとプロキシ コード ファイルが生成されたフォルダに移動します。
- ファイルを選択し、[OK] をクリックします。
プロキシ コードと構成ファイルを生成したら、ローカル ホスト通信を容易にするために使用される新しいクライアント エンドポイントがホスト アプリケーションから認識されるように、App.config 内の構成コードを変更します。また、必要に応じて、ワークフロー サービスとの通信に現在使用されているバインディング構成情報と同じバインディング構成情報を使用することもできます。次のコード例は、App.Config ファイルに追加するコードを示しています。
<bindings> ... </bindings> <client> <endpoint address="https://localhost:8080/ServerWorkflow" binding="wsHttpContextBinding" bindingConfiguration="WSHttpContextBinding_IWorkflow1" contract="IWorkflow1" name="WSHttpContextBinding_IWorkflow1"> <identity> <userPrincipalName value="someone@example.com" /> </identity> </endpoint> <endpoint address="https://localhost:8090/ClientWorkflow" binding="wsHttpContextBinding" bindingConfiguration="WSHttpContextBinding_IWorkflow1" contract="ILocalHostContract" name="WSHttpContextBinding_ILocalHostContract"> <identity> <userPrincipalName value="someone@example.com" /> </identity> </endpoint> </client> <services> ... </services> <behaviors> ... </behaviors>
ホストとワークフロー サービス クライアントとの間で通信を行うためのプロキシ クライアント コードを生成したので、今度は、LocalHostContractClient.StartClientWorkflow 操作を呼び出すためのコードをクライアント ワークフローに追加する必要があります。Program.cs (Visual Basic ソリューションを作成した場合は Module1.vb) を開き、次のコードを追加します。
Class Program Shared WaitHandle As New AutoResetEvent(False) Shared Sub Main() ' Create a WorkflowServiceHost object to listen for operation invocations. Using ConsoleHost As New WorkflowServiceHost(GetType(WorkflowServiceClient.ClientWorkflow)) Dim waitHandle As New AutoResetEvent(False) ' Create a client that is used by the host application to communicate with the workflow service client. Dim LCSClient As New WorkflowServiceClient.LocalHostContractClient("WSHttpContextBinding_ILocalHostContract") ' Add ChannelManagerService to the list of services used ' by the WorkflowRuntime. Dim cms As New ChannelManagerService() ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.AddService(cms) AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowCompleted, AddressOf OnWorkflowCompleted AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowTerminated, AddressOf OnWorkflowTerminated AddHandler ConsoleHost.Closed, AddressOf OnConsoleClosed ' Call Open to start receiving messages. ConsoleHost.Open() Console.WriteLine("Client host service is ready.") Console.WriteLine("Enter a starting value: ") ' Read in a number from the user and use it as the initial number in the arithmetic operation calls. LCSClient.StartClientWorkflow(Int32.Parse(Console.ReadLine())) ' After the client workflow is started, block until receiving waitHandle.Set is called ' so that the console application does not exit before the client workflow has completed ' and ConsoleHost.Close is called. waitHandle.WaitOne() End Using End Sub Shared Sub OnWorkflowCompleted(ByVal sender As Object, ByVal e As WorkflowCompletedEventArgs) Console.WriteLine("The client workflow has completed." + vbLf + "Press <Enter> to exit the client application.") Console.ReadLine() WaitHandle.Set() End Sub Shared Sub OnWorkflowTerminated(ByVal sender As Object, ByVal e As WorkflowTerminatedEventArgs) Console.WriteLine(e.Exception.Message) WaitHandle.Set() End Sub ' After the WorkflowServiceHost transitions to the closed state, allow the console ' application to exit by signaling to the AutoResetEvent object that it is okay to unblock ' the main thread. Shared Sub OnConsoleClosed(ByVal sender As Object, ByVal e As EventArgs) WaitHandle.Set() End Sub End Class
static void Main(string[] args) { // Create a WorkflowServiceHost object to listen for operation invocations. using (WorkflowServiceHost ConsoleHost = new WorkflowServiceHost(typeof(ClientWorkflow))) { AutoResetEvent waitHandle = new AutoResetEvent(false); // Create a client that is used by the host application to communicate with the workflow service client. LocalHostContractClient LCSClient = new LocalHostContractClient("WSHttpContextBinding_ILocalHostContract"); // Add ChannelManagerService to the list of services used // by the WorkflowRuntime. ChannelManagerService cms = new ChannelManagerService(); ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.AddService(cms); ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { Console.WriteLine("The client workflow has completed. \nPress <Enter> to exit the client application."); Console.ReadLine(); ConsoleHost.Close(); }; ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine(e.Exception.Message); waitHandle.Set(); }; // After the WorkflowServiceHost transitions to the closed state, allow the console // application to exit by signaling to the AutoResetEvent object that it is okay to unblock // the main thread. ConsoleHost.Closed += delegate(object sender, EventArgs e) { waitHandle.Set(); }; // Call Open to start receiving messages. ConsoleHost.Open(); Console.WriteLine("Client host service is ready."); Console.WriteLine("Enter a starting value: "); // Read in a number from the user and use it as the initial number in the arithmetic operation calls. LCSClient.StartClientWorkflow(Int32.Parse(Console.ReadLine())); // After the client workflow is started, block until receiving waitHandle.Set is called // so that the console application does not exit before the client workflow has completed and // ConsoleHost.Close is called. waitHandle.WaitOne(); } }
この操作を実装する ReceiveActivity では CanCreateInstance が True に設定されているため、新しいワークフロー インスタンスが作成され、ワークフローの残りの部分は、これよりも前の演習と同様に実行されます。また、コマンド プロンプトで入力される値が最初のシード値になり、ワークフロー サービスに対して残りの算術演算を呼び出すときに使用されます。
Workflow1.cs (Visual Basic ソリューションを作成した場合は Workflow1.vb) を開き、sendActivity2_BeforeSend メソッドの実装の中の、inputValue 変数に数字 1 を代入するコード行を削除します。ユーザーがコマンド プロンプトで値を入力すると、その値が、ワークフロー サービスに対するすべての操作呼び出しの、最初のシード値として使用されるようにするためです。次のコード例は、改訂後のイベント ハンドラ メソッドの実装がどのようになるかを示しています。
Private Sub sendActivity2_BeforeSend(ByVal sender As System.Object, ByVal e As System.Workflow.Activities.SendActivityEventArgs) Console.WriteLine("The initial input value is {0}", inputValue) End Sub
private void sendActivity2_BeforeSend(object sender, SendActivityEventArgs e) { Console.WriteLine("The initial input value is {0}", inputValue); }
WorkflowServiceTutorial ソリューションをビルドし、実行します。コンソール ホスト アプリケーションからの、次のような出力を確認できます。
Client host service is ready. Enter a starting value: 7 A service instance has successfully been created. The initial input value is 7 The value after invoking the Add operation is 7 The new input value is 2 The value after invoking the Subtract operation is 5 The new input value is 6 The value after invoking the Multiply operation is 30 The new input value is 3 The value after invoking the Divide operation is 10 The workflow service instance has successfully shutdown. The client workflow has completed. Press <Enter> to exit the client application.
関連項目
リファレンス
Copyright © 2007 by Microsoft Corporation. All rights reserved.