次の方法で共有


ワークフロー サービスへのトランザクションのフロー

ワークフロー サービスとワークフロー クライアントはトランザクションに参加できます。 サービス操作をアンビエント トランザクションの一部にするには、Receive アクティビティを TransactedReceiveScope アクティビティの中に配置します。 Send 内の SendReply または TransactedReceiveScope アクティビティによる呼び出しが行われると、アンビエント トランザクション内でも呼び出しが行われます。 ワークフロー クライアント アプリケーションでは、TransactionScope アクティビティを使用してアンビエント トランザクションを作成し、そのアンビエント トランザクションを使用してサービス操作を呼び出すことができます。 ここでは、トランザクションに参加するワークフロー サービスとワークフロー クライアントを作成する手順について説明します。

警告

ワークフロー サービス インスタンスがトランザクション内に読み込まれて、ワークフローに Persist アクティビティが含まれている場合、ワークフロー インスタンスはトランザクションがタイムアウトになるまでブロックされます。

重要

TransactedReceiveScope を使用する場合は、ワークフロー内のすべての受信を TransactedReceiveScope アクティビティに配置することをお勧めします。

重要

TransactedReceiveScope を使用して、メッセージが不適切な順序で到着する場合、最初の順序を無視したメッセージを配信しようとするとワークフローは中止されます。 ワークフローがアイドル状態である場合、ワークフローは常に一致する停止ポイントにあるようにする必要があります。 これによって、ワークフローが中止された場合、前の永続性ポイントからワークフローを再開することができます。

共有ライブラリの作成

  1. 新しい空の Visual Studio ソリューションを作成します。

  2. Common という新しいクラス ライブラリ プロジェクトを追加します。 次のアセンブリへの参照を追加します。

    • System.Activities.dll

    • System.ServiceModel.dll

    • System.ServiceModel.Activities.dll

    • System.Transactions.dll

  3. PrintTransactionInfo という新しいクラスを Common プロジェクトに追加します。 このクラスは 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);  
                }  
            }  
        }  
    
    }  
    

    これは、アンビエント トランザクションに関する情報を表示するネイティブ アクティビティで、ここで使用するサービス ワークフローとクライアント ワークフローの両方で使用されます。 ソリューションをビルドして、このアクティビティを [ツールボックス][Common] セクションで使用できるようにします。

ワークフロー サービスの実装

  1. WorkflowService という新しい WCF ワークフロー サービスを Common プロジェクトに追加します。 そのためには、Common プロジェクトを右クリックし、[追加][新しい項目] の順に選択します。次に、[インストールされているテンプレート][ワークフロー] を選び、[WCF ワークフロー サービス] を選択します。

    Adding a Workflow Service

  2. 既定の ReceiveRequest アクティビティと SendResponse アクティビティを削除します。

  3. WriteLine アクティビティを Sequential Service アクティビティにドラッグ アンド ドロップします。 次の例に示すように、Text プロパティを "Workflow Service starting ..." に設定します。

    ![シーケンシャル サービス アクティビティへの WriteLine アクティビティの追加 (./media/flowing-transactions-into-and-out-of-workflow-services/add-writeline-sequential-service.jpg)

  4. TransactedReceiveScopeWriteLine アクティビティの後にドラッグ アンド ドロップします。 TransactedReceiveScope アクティビティは、[ツールボックス][Messaging] セクションにあります。 TransactedReceiveScope アクティビティは、RequestBody の 2 つのセクションで構成されています。 Request セクションには、Receive アクティビティが含まれます。 Body セクションには、メッセージの受信後にトランザクション内で実行されるアクティビティが含まれます。

    Adding a TransactedReceiveScope activity

  5. TransactedReceiveScope アクティビティを選択し、[変数] ボタンをクリックします。 次の変数を追加します。

    Adding variables to the TransactedReceiveScope

    Note

    既定で含まれているデータ変数は削除してかまいません。 既存のハンドル変数を使用することもできます。

  6. Receive アクティビティを TransactedReceiveScope アクティビティの Request セクションにドラッグ アンド ドロップします。 次のプロパティを設定します。

    Property [値]
    CanCreateInstance True (チェック ボックスをオンにする)
    OperationName StartSample
    ServiceContractName ITransactionSample

    ワークフローは次のようになります。

    Adding a Receive activity

  7. Receive アクティビティの [定義...] リンクをクリックし、次の設定を行います。

    Setting message settings for the Receive activity

  8. Sequence アクティビティを TransactedReceiveScope の Body セクションにドラッグ アンド ドロップします。 Sequence アクティビティに 2 つの WriteLine アクティビティをドラッグ アンド ドロップし、Text プロパティを次の表のとおりに設定します。

    アクティビティ [値]
    1 つ目の WriteLine "Service: Receive Completed"
    2 つ目の WriteLine "Service: Received = " + requestMessage

    ワークフローは次のようになります。

    Sequence after adding WriteLine activities

  9. PrintTransactionInfo アクティビティを、TransactedReceiveScope アクティビティの Body の 2 つ目の WriteLine アクティビティの後にドラッグ アンド ドロップします。

    Sequence after adding PrintTransactionInfo

  10. Assign アクティビティを PrintTransactionInfo アクティビティの後にドラッグ アンド ドロップし、次の表のとおりにプロパティを設定します。

    プロパティ [値]
    終了 replyMessage
    [値] "Service: Sending reply."
  11. WriteLine アクティビティを Assign アクティビティの後にドラッグ アンド ドロップし、Text プロパティを "Service: Begin reply" に設定します。

    ワークフローは次のようになります。

    After adding Assign and WriteLine

  12. Receive アクティビティを右クリックして [SendReply の作成] を選択し、最後の WriteLine アクティビティの後に貼り付けます。 SendReplyToReceive アクティビティの [定義...] リンクをクリックし、次の設定を行います。

    Reply message settings

  13. WriteLine アクティビティを SendReplyToReceive アクティビティの後にドラッグ アンド ドロップし、Text プロパティを "Service: Reply sent" に設定します。

  14. WriteLine アクティビティをワークフローの末尾にドラッグ アンド ドロップし、Text プロパティを "Service: Workflow ends, press ENTER to exit" に設定します。

    完成したサービス ワークフローは次のようになります。

    Complete Service Workflow

ワークフロー クライアントの実装

  1. WorkflowClient という新しい WCF ワークフロー アプリケーションを Common プロジェクトに追加します。 そのためには、Common プロジェクトを右クリックし、[追加][新しい項目] の順に選択します。次に、[インストールされているテンプレート][ワークフロー] を選び、[アクティビティ] を選択します。

    Add an Activity project

  2. Sequence アクティビティをデザイン画面にドラッグ アンド ドロップします。

  3. Sequence アクティビティを WriteLine アクティビティにドラッグ アンド ドロップし、Text プロパティを "Client: Workflow starting" に設定します。 ワークフローは次のようになります。

    Add a WriteLine activity

  4. TransactionScope アクティビティを WriteLine アクティビティの後にドラッグ アンド ドロップします。 TransactionScope アクティビティを選択し、[変数] をクリックして次の変数を追加します。

    Add variables to the TransactionScope

  5. Sequence アクティビティを TransactionScope アクティビティの Body セクションにドラッグ アンド ドロップします。

  6. PrintTransactionInfo アクティビティを Sequence アクティビティにドラッグ アンド ドロップします。

  7. WriteLine アクティビティを PrintTransactionInfo アクティビティの後にドラッグ アンド ドロップし、その Text プロパティを "Client: Beginning Send" に設定します。 ワークフローは次のようになります。

    Adding Client: Beginning Send activities

  8. Send アクティビティを Assign アクティビティの後にドラッグ アンド ドロップし、次のプロパティを設定します。

    プロパティ [値]
    EndpointConfigurationName workflowServiceEndpoint
    OperationName StartSample
    ServiceContractName ITransactionSample

    ワークフローは次のようになります。

    Setting the Send activity properties

  9. [定義...] リンクをクリックし、次の設定を行います。

    Send activity message settings

  10. Send アクティビティを右クリックし、[ReceiveReply の作成] を選択します。 ReceiveReply アクティビティが Send アクティビティの後に自動的に配置されます。

  11. ReceiveReplyForSend アクティビティの [定義] リンクをクリックし、次の設定を行います。

    Setting the ReceiveForSend message settings

  12. WriteLine アクティビティを Send アクティビティと ReceiveReply アクティビティの間にドラッグ アンド ドロップし、Text プロパティを "Client: Send complete" に設定します。

  13. WriteLine アクティビティを ReceiveReply アクティビティの後にドラッグ アンド ドロップし、Text プロパティを "Client side: Reply received = " + replyMessage に設定します。

  14. PrintTransactionInfo アクティビティを WriteLine アクティビティの後にドラッグ アンド ドロップします。

  15. WriteLine アクティビティをワークフローの末尾にドラッグ アンド ドロップし、Text プロパティを "Client workflow ends" に設定します。完成したクライアント ワークフローは次の図のようになります。

    The completed client workflow

  16. ソリューションをビルドします。

サービス アプリケーションの作成

  1. Service という新しいコンソール アプリケーション プロジェクトをソリューションに追加します。 次のアセンブリへの参照を追加します。

    1. System.Activities.dll

    2. System.ServiceModel.dll

    3. System.ServiceModel.Activities.dll

  2. 生成された 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();  
              };
          }  
    
  3. 次の 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>  
    

クライアント アプリケーションを作成する

  1. Client という新しいコンソール アプリケーション プロジェクトをソリューションに追加します。 System.Activities.dll への参照を追加します。

  2. 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;  
        }  
    }  
    

関連項目