共用方式為


進出工作流程服務的異動流動

工作流程服務與用戶端都可以參與交易。 若要讓服務作業變成環境交易的一部分,請將 Receive 活動放在 TransactedReceiveScope 活動內。 SendSendReply 活動在 TransactedReceiveScope 內所進行的任何呼叫也會在環境交易中進行。 工作流程用戶端應用程式可以使用 TransactionScope 活動建立環境異動,然後使用環境異動呼叫服務作業。 本主題逐步帶領您建立參與交易的工作流程服務和工作流程用戶端。

警告

如果工作流程服務執行個體是在異動內載入,且工作流程包含 Persist 活動,則工作流程執行個體將會阻塞,直到異動逾時為止。

重要

每當您使用 TransactedReceiveScope 時,建議您將工作流程中的所有 Receive 放在 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);  
                }  
            }  
        }  
    
    }  
    

    這是一種原生活動,該活動可顯示環境異動的相關資訊,而且可同時用於本主題中所使用的服務和用戶端工作流程。 建置解決方案可讓此活動在 [工具箱] 的 [通用] 區段中使用。

實作工作流程服務

  1. 將稱為 WorkflowService 的新 WCF 工作流程服務新增至 Common 專案。 若要這樣做,請以滑鼠右鍵按一下 Common 專案、依序選取 [新增]、[新增項目]、[已安裝的範本] 底下的 [工作流程] 和 [WCF 工作流程服務]

    Adding a Workflow Service

  2. 刪除預設的 ReceiveRequestSendResponse 活動。

  3. WriteLine 活動拖放到 Sequential Service 活動中。 將文字屬性設定為 "Workflow Service starting ...",如下列範例所示。

    ![將 WriteLine 活動新增至循序服務活動(./media/flowing-transactions-into-and-out-of-workflow-services/add-writeline-sequential-service.jpg)

  4. TransactedReceiveScope 拖放到 WriteLine 活動後面。 TransactedReceiveScope 活動可以在 [工具箱]Toolbox 的 [傳訊] 區段中找到。 TransactedReceiveScope 活動是由 [要求] 和 [主體] 兩個區段所組成。 [要求] 區段包含 Receive 活動。 [主體] 區段包含接收訊息後,要在異動內執行的活動。

    Adding a TransactedReceiveScope activity

  5. 選取 TransactedReceiveScope 活動,然後按一下 [變數] 按鈕。 加入下列變數。

    Adding variables to the TransactedReceiveScope

    注意

    根據預設,您可以刪除現有的資料變數。 您也可以使用現有的控制碼變數。

  6. Receive 活動拖放到 TransactedReceiveScope 活動的 [要求] 區段內。 設定下列屬性:

    屬性
    CanCreateInstance True (核取此核取方塊)
    OperationName StartSample
    ServiceContractName ITransactionSample

    工作流程的外觀應該如下圖所示:

    Adding a Receive activity

  7. 按一下 Receive 活動中的 [定義] 連結,然後進行下列設定:

    Setting message settings for the Receive activity

  8. Sequence 活動拖放到 TransactedReceiveScope 的 [主體] 區段內。 拖放 Sequence 活動內的兩個 WriteLine 活動,並設定 Text 屬性,如下列範例所示。

    活動
    第一個 WriteLine "Service: Receive Completed"
    第二個 WriteLine "Service: Received = " + requestMessage

    工作流程的外觀現在應該如下圖所示:

    Sequence after adding WriteLine activities

  9. PrintTransactionInfo 活動拖放到 TransactedReceiveScope 活動中 [主體] 的第二個 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 活動的主體內。

  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 活動拖放到 SendReceiveReply 活動之間,然後將其 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;  
        }  
    }  
    

另請參閱