共用方式為


將交易流進和流出工作流程服務

工作流程服務和用戶端可以參與交易。 若要讓服務作業成為環境交易的一部分,請將 Receive 活動放在 TransactedReceiveScope 活動內。 任何由 SendSendReply 活動在 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);  
                }  
            }  
        }  
    
    }  
    

    這是原生活動,會顯示環境交易的相關信息,並用於本主題中使用的服務和用戶端工作流程。 建置方案,讓此活動可在 [工具箱] 的 [一般] 區段中使用。

實作工作流程服務

  1. 將名為 WorkflowService 的新 WCF 工作流程服務新增至 Common 專案。 若要以滑鼠右鍵按兩下Common專案,請選取 [新增]、[新增專案...],選取 [已安裝的範本] 下的 [工作流程],然後選取 [WCF 工作流程服務]。

    新增工作流程服務

  2. 刪除預設活動 ReceiveRequestSendResponse

  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可以在 [工具箱] 的 [傳訊] 區段中找到。 活動由兩個區段組成,分別是TransactedReceiveScope本文[要求] 區段包含Receive活動。 主體區段包含在接收訊息之後,於交易內執行的活動。

    新增 TransactedReceiveScope 活動

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

    將變數新增至 TransactedReceiveScope

    備註

    您可以刪除預設有的數據變數。 您也可以使用現有的句柄變數。

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

    房產 價值觀
    可以建立實例 True (核取複選框)
    作業名稱 開始示例
    服務合約名稱 ITransactionSample

    工作流程看起來應該像這樣:

    新增接收活動

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

    設定接收活動的訊息設定

  8. Sequence活動拖放到TransactedReceiveScope的Body區段中。 在 Sequence 活動中拖放兩個 WriteLine 活動,並設定 Text 屬性,如下表所示。

    活動 價值觀
    第 1 個「WriteLine」 “服務:接收已完成”
    第 2 個 WriteLine 服務:Received = " + requestMessage

    工作流程現在看起來應該像這樣:

    新增 WriteLine 活動之後的順序

  9. PrintTransactionInfo活動的WriteLine中,將活動拖放到第二個TransactedReceiveScope活動之後。

    新增 PrintTransactionInfo 之後的順序

  10. Assign活動拖放至PrintTransactionInfo活動之後,並根據下表設定其屬性。

    房產 價值觀
    發往 回覆訊息
    價值觀 「服務:傳送回復。」
  11. WriteLine活動拖放到Assign活動之後,並將其Text屬性設定為「服務:開始回復」。

    工作流程現在看起來應該像這樣:

    新增 Assign 和 WriteLine 之後

  12. 以滑鼠右鍵按兩下 Receive 活動,然後選取 [建立 SendReply ],並將它貼到最後一個 WriteLine 活動之後。 點擊 活動中的 SendReplyToReceive 連結,然後進行下列設定。

    回復訊息設定

  13. WriteLine活動拖放到SendReplyToReceive活動之後,並將其Text屬性設定為「服務:已傳送回復」。

  14. 在工作流程底部拖放一個WriteLine活動,然後將其Text屬性設置為「服務:工作流程結束,按 ENTER 鍵退出」。

    已完成的服務工作流程看起來應該像這樣:

    完成服務工作流程

實作工作流程用戶端

  1. 將名為 WorkflowClient 的新 WCF 工作流程應用程式新增至 Common 專案。 若要以滑鼠右鍵按兩下Common專案,請選取 [新增]、[新增專案...],選取 [已安裝的範本] 下的 [工作流程],然後選取 [活動]。

    新增活動專案

  2. Sequence活動拖放至設計介面。

  3. Sequence活動內拖放WriteLine活動,並將Text屬性設定為"Client: Workflow starting"。 工作流程現在看起來應該像這樣:

    新增 WriteLine 活動

  4. TransactionScope將活動拖放到WriteLine活動之後。 選取活動,按兩下 [ TransactionScope 變數] 按鈕並新增下列變數。

    將變數新增至 TransactionScope

  5. Sequence活動拖放到TransactionScope活動的主體中。

  6. PrintTransactionInfo中拖放Sequence活動

  7. WriteLine活動拖放到PrintTransactionInfo活動之後,並將其Text屬性設定為「客戶端:開始傳送」。 工作流程現在看起來應該像這樣:

    新增客戶端:開始傳送活動

  8. Send活動拖放到Assign活動之後,並設定下列屬性:

    房產 價值觀
    EndpointConfigurationName (端點配置名稱) 工作流程服務端點
    作業名稱 開始範例
    服務合約名稱 ITransactionSample

    工作流程現在看起來應該像這樣:

    設定傳送活動屬性

  9. 按兩下 [ 定義... ] 連結,然後進行下列設定:

    傳送活動訊息設定

  10. Send 活動上滑鼠右鍵點擊,然後選擇 建立 ReceiveReply。 活動 ReceiveReply 將會自動放置在活動 Send 之後。

  11. 點擊 ReceiveReplyForSend 活動上的「定義...」連結,並進行下列設定:

    設定 ReceiveForSend 訊息設定

  12. 將一個WriteLine活動拖放至SendReceiveReply活動之間,並將其Text屬性設定為「客戶:全數發送」。

  13. WriteLine活動拖放至ReceiveReply活動之後,並將其Text屬性設定為 "Client side:Reply received = " + replyMessage

  14. PrintTransactionInfo將活動拖放到WriteLine活動之後。

  15. 將一個WriteLine活動拖放到工作流程結尾,並將其Text屬性設為「用戶端工作流程結束」。已完成的用戶端工作流程應該看起來像下圖。

    已完成的用戶端工作流程

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

另請參閱