ワークフロー サービスとクライアントはトランザクションに参加できます。 サービス操作をアンビエント トランザクションの一部にするには、TransactedReceiveScope アクティビティ内にReceive アクティビティを配置します。 TransactedReceiveScope内のSendまたはSendReply アクティビティによって行われた呼び出しも、アンビエント トランザクション内で行われます。 ワークフロー クライアント アプリケーションは、 TransactionScope アクティビティを使用してアンビエント トランザクションを作成し、アンビエント トランザクションを使用してサービス操作を呼び出すことができます。 このトピックでは、トランザクションに参加するワークフロー サービスとワークフロー クライアントを作成する手順について説明します。
Warnung
ワークフロー サービス インスタンスがトランザクション内に読み込まれ、ワークフローに Persist アクティビティが含まれている場合、ワークフロー インスタンスはトランザクションがタイムアウトするまでブロックされます。
Von Bedeutung
TransactedReceiveScopeを使用する場合は常に、すべての受信をTransactedReceiveScopeアクティビティ内のワークフローに配置することをお勧めします。
Von Bedeutung
TransactedReceiveScopeを使用し、メッセージが正しくない順序で到着すると、最初の順序外メッセージを配信しようとするとワークフローが中止されます。 ワークフローがアイドル状態になったときに、ワークフローが常に一貫した停止ポイントにあることを確認する必要があります。 これにより、ワークフローを中止した場合に、以前の永続化ポイントからワークフローを再起動できます。
共有ライブラリを作成する
新しい空の Visual Studio ソリューションを作成します。
Common
という名前の新しいクラス ライブラリ プロジェクトを追加します。 次のアセンブリへの参照を追加します。System.Activities.dll
System.ServiceModel.dll
System.ServiceModel.Activities.dll
System.Transactions.dll
Common
プロジェクトにPrintTransactionInfo
という新しいクラスを追加します。 このクラスは NativeActivity から派生し、 Execute メソッドをオーバーロードします。using System; using System; using System.Activities; using System.Transactions; namespace Common { public class PrintTransactionInfo : NativeActivity { protected override void Execute(NativeActivityContext context) { RuntimeTransactionHandle rth = context.Properties.Find(typeof(RuntimeTransactionHandle).FullName) as RuntimeTransactionHandle; if (rth == null) { Console.WriteLine("There is no ambient RuntimeTransactionHandle"); } Transaction t = rth.GetCurrentTransaction(context); if (t == null) { Console.WriteLine("There is no ambient transaction"); } else { Console.WriteLine("Transaction: {0} is {1}", t.TransactionInformation.DistributedIdentifier, t.TransactionInformation.Status); } } } }
これは、アンビエント トランザクションに関する情報を表示するネイティブ アクティビティであり、このトピックで使用されるサービス ワークフローとクライアント ワークフローの両方で使用されます。 ツールボックスの [共通 ] セクションでこのアクティビティを使用できるようにするためのソリューションをビルド します。
ワークフロー サービスを実装する
WorkflowService
と呼ばれる新しい WCF ワークフロー サービスをCommon
プロジェクトに追加します。 これを行うには、Common
プロジェクトを右クリックし、[追加]、[新しい項目]、[インストールされているテンプレート] の [ワークフロー] の順に選択し、[WCF ワークフロー サービス] を選択します。既定の
ReceiveRequest
とSendResponse
アクティビティを削除します。WriteLine アクティビティを
Sequential Service
アクティビティにドラッグ アンド ドロップします。 次の例に示すように、text プロパティを"Workflow Service starting ..."
に設定します。![順次サービス アクティビティへの WriteLine アクティビティの追加 (./media/flowing-transactions-into-and-out-of-workflow-services/add-writeline-sequential-service.jpg)
WriteLine アクティビティの後にTransactedReceiveScopeをドラッグ アンド ドロップします。 TransactedReceiveScopeアクティビティは、ツールボックスの [メッセージング] セクションにあります。 TransactedReceiveScope アクティビティは、要求と本文の 2 つのセクションで構成されます。 [要求] セクションには、Receiveアクティビティが含まれています。 [本文] セクションには、メッセージの受信後にトランザクション内で実行するアクティビティが含まれます。
TransactedReceiveScopeアクティビティを選択し、[変数] ボタンをクリックします。 次の変数を追加します。
注
既定で存在するデータ変数を削除できます。 既存のハンドル変数を使用することもできます。
TransactedReceiveScope アクティビティの [要求] セクション内で、Receive アクティビティをドラッグ アンド ドロップします。 次のようにプロパティを設定します。
プロパティ 価値 CanCreateInstance True (チェック ボックスをオン) オペレーションネーム StartSample ServiceContractName ITransactionSample ワークフローは次のようになります。
Receive アクティビティの [定義...] リンクをクリックし、次の設定を行います。
TransactedReceiveScopeの [本文] セクションにSequenceアクティビティをドラッグ アンド ドロップします。 Sequence アクティビティ内で、2 つのWriteLine アクティビティをドラッグ アンド ドロップし、次の表に示すようにTextプロパティを設定します。
活動 価値 1st WriteLine "サービス: 受信完了" 2 番目の WriteLine "Service: Received = " + requestMessage ワークフローは次のようになります。
TransactedReceiveScope アクティビティの Body の 2 番目のWriteLine アクティビティの後に、
PrintTransactionInfo
アクティビティをドラッグ アンド ドロップします。PrintTransactionInfo
アクティビティの後にAssign アクティビティをドラッグ アンド ドロップし、次の表に従ってプロパティを設定します。プロパティ 価値 移行先 replyMessage 価値 "サービス: 応答の送信" Assign アクティビティの後にWriteLine アクティビティをドラッグ アンド ドロップし、そのText プロパティを "Service: Begin reply" に設定します。
ワークフローは次のようになります。
Receive アクティビティを右クリックし、[SendReply の作成] を選択し、最後のWriteLine アクティビティの後に貼り付けます。
SendReplyToReceive
アクティビティの [定義...] リンクをクリックし、次の設定を行います。SendReplyToReceive
アクティビティの後にWriteLine アクティビティをドラッグ アンド ドロップし、Text プロパティを "Service: Reply sent" に設定します。ワークフローの下部にある WriteLine アクティビティをドラッグ アンド ドロップし、その Text プロパティを "サービス: ワークフローの終了、Enter キーを押して終了" に設定します。
完成したサービス ワークフローは次のようになります。
ワークフロー クライアントを実装する
WorkflowClient
と呼ばれる新しい WCF ワークフロー アプリケーションをCommon
プロジェクトに追加します。 これを行うには、Common
プロジェクトを右クリックし、[追加]、[新しい項目]、[インストールされているテンプレート] の下の [ワークフロー] の順に選択し、[アクティビティ] を選択します。Sequence アクティビティをデザイン サーフェイスにドラッグ アンド ドロップします。
Sequence アクティビティ内で、WriteLine アクティビティをドラッグ アンド ドロップし、そのTextプロパティを
"Client: Workflow starting"
に設定します。 ワークフローは次のようになります。WriteLine アクティビティの後にTransactionScope アクティビティをドラッグ アンド ドロップします。 TransactionScopeアクティビティを選択し、[変数] ボタンをクリックして、次の変数を追加します。
TransactionScope アクティビティの本文にSequence アクティビティをドラッグ アンド ドロップします。
内の
PrintTransactionInfo
アクティビティをドラッグ アンド ドロップします。 SequencePrintTransactionInfo
アクティビティの後にWriteLine アクティビティをドラッグ アンド ドロップし、そのText プロパティを "Client: Beginning Send" に設定します。 ワークフローは次のようになります。Assign アクティビティの後にSend アクティビティをドラッグ アンド ドロップし、次のプロパティを設定します。
プロパティ 価値 EndpointConfigurationName workflowServiceEndpoint オペレーションネーム StartSample ServiceContractName ITransactionSample ワークフローは次のようになります。
[ 定義... ] リンクをクリックし、次の設定を行います。
Send アクティビティを右クリックし、[ReceiveReply の作成] を選択します。 ReceiveReply アクティビティは、Send アクティビティの後に自動的に配置されます。
[定義]をクリックします。..ReceiveReplyForSend アクティビティのリンクをクリックし、次の設定を行います。
SendアクティビティとReceiveReplyアクティビティの間でWriteLineアクティビティをドラッグ アンド ドロップし、そのTextプロパティを "Client: Send complete" に設定します。
ReceiveReply アクティビティの後にWriteLine アクティビティをドラッグ アンド ドロップし、そのTextプロパティを "クライアント側: 受信した応答 = " + replyMessage に設定します
WriteLine アクティビティの後に
PrintTransactionInfo
アクティビティをドラッグ アンド ドロップします。ワークフローの最後に WriteLine アクティビティをドラッグ アンド ドロップし、その Text プロパティを "クライアント ワークフローの終了" に設定します。完成したクライアント ワークフローは、次の図のようになります。
ソリューションをビルドします。
サービス アプリケーションを作成する
Service
という名前の新しいコンソール アプリケーション プロジェクトをソリューションに追加します。 次のアセンブリへの参照を追加します。System.Activities.dll
System.ServiceModel.dll
System.ServiceModel.Activities.dll
生成されたProgram.cs ファイルと次のコードを開きます。
static void Main() { Console.WriteLine("Building the server."); using (WorkflowServiceHost host = new WorkflowServiceHost(new DeclarativeServiceWorkflow(), new Uri("net.tcp://localhost:8000/TransactedReceiveService/Declarative"))) { //Start the server host.Open(); Console.WriteLine("Service started."); Console.WriteLine(); Console.ReadLine(); //Shutdown host.Close(); }; }
次の app.config ファイルをプロジェクトに追加します。
<?xml version="1.0" encoding="utf-8" ?> <!-- Copyright © Microsoft Corporation. All rights reserved. --> <configuration> <system.serviceModel> <bindings> <netTcpBinding> <binding transactionFlow="true" /> </netTcpBinding> </bindings> </system.serviceModel> </configuration>
クライアント アプリケーションを作成する
Client
という名前の新しいコンソール アプリケーション プロジェクトをソリューションに追加します。 System.Activities.dllへの参照を追加します。program.cs ファイルを開き、次のコードを追加します。
class Program { private static AutoResetEvent syncEvent = new AutoResetEvent(false); static void Main(string[] args) { //Build client Console.WriteLine("Building the client."); WorkflowApplication client = new WorkflowApplication(new DeclarativeClientWorkflow()); client.Completed = Program.Completed; client.Aborted = Program.Aborted; client.OnUnhandledException = Program.OnUnhandledException; //Wait for service to start Console.WriteLine("Press ENTER once service is started."); Console.ReadLine(); //Start the client Console.WriteLine("Starting the client."); client.Run(); syncEvent.WaitOne(); //Sample complete Console.WriteLine(); Console.WriteLine("Client complete. Press ENTER to exit."); Console.ReadLine(); } private static void Completed(WorkflowApplicationCompletedEventArgs e) { Program.syncEvent.Set(); } private static void Aborted(WorkflowApplicationAbortedEventArgs e) { Console.WriteLine("Client Aborted: {0}", e.Reason); Program.syncEvent.Set(); } private static UnhandledExceptionAction OnUnhandledException(WorkflowApplicationUnhandledExceptionEventArgs e) { Console.WriteLine("Client had an unhandled exception: {0}", e.UnhandledException); return UnhandledExceptionAction.Cancel; } }