天天看點

工作流程式設計循序漸進(7:InvokeWorkflowActivity活動) 工作流程式設計循序漸進(7:InvokeWorkflowActivity活動) 五、添加HandleExternalEventActivity活動 六、定義在工作流執行個體與宿主間通信的本地服務七、在宿主中操作工作流執行個體與本地服務九、參考資料

作者  朱先忠

      使用InvokeWorkflowActivity 活動可以從一個工作流中<b>異步方式</b>啟動另一個工作流。 在已啟動的工作流開始執行且工作流分支中的下一個活動執行之前,InvokeWorkflowActivity 活動即告完成。

<b>注意:</b>

<b>WF不支援遞歸工作流。如果工作流A能夠啟動工作流B,則工作流B既不能直接啟動工作流A,也不能啟動任何直接或間接調用工作流A的工作流。</b>

<b>InvokeWorkflowActivity活動要求工作流運作時使用目前附加到該運作時的計劃程式服務建立新工作流。</b>

<b>所調用的工作流将隻能夠接收輸入參數。不支援在工作流完成之後擷取輸出參數,因為該活動以異步方式調用工作流。</b>

<b>工作流之間的标準通信規則适用于與InvokeWorkflowActivny活動所建立的新工作流執行個體進行通信。</b>

使用InvokeWorkflowActivity活動的步驟如下:

   拖動一個InvokeWorkflowActivity到工作流中希望的位置處。

   設定TargetWorkflow屬性為希望執行的工作流的類型(Type)。

   為TargetWorkflow設定所需要的值。

      當設定TargetWorkflow屬性時,該活動提供了對話框允許從所有引用到的活動類型清單中導航到正确的類型,但是隻有派生自Activity的類 會被顯示在清單中。為了引用一個新的工作流類型,必須首先添加到包含工作流的項目或程式集的引用。具體對話框請參考本文後面的圖示。

      一旦定義了TargetWorkflow屬性,工作流的參數集合屬性将使用定義在TargetWorkflow中的其他任何屬性所更新。允許開發人員在屬性視窗中為任何所需的屬性設定值,可以設定靜态值或者是綁定屬性到目前工作流的其他屬性或者是其他活動的其他屬性。

      InvokeWorkflowActivity提供了一個Invoking事件允許開發人員使用代碼處理。該事件在建立一個新的工作流之前觸發,這使開發人員在開始一個新的工作流之前能夠有機會完成一些設定任務。

關于InvokeWorkflowActiv時的一個重要方面工作流将以異步的方式執行,是以不會等待新工作流的執行完成。因為執行過程是異步的,是以無法擷取另一個工作流的輸出參數。<b>通常需要和宿主建立額外的通信機制來擷取其輸出。</b>

       <b>說明</b>:本文建立的InvokeWorkflowActivityDemo示例示範了如何在一個狀态機工作流内部調用另外的一個工作SubWorkflow,并且定義了本地服務接口實作,使用HandleExternalEvent活動調用外部事件以等待被調用的工作流執行個體執行完成。該活動需要等待一個事件的觸發才能夠繼續工作流的運作,而在Program.cs中,設定了隻有當指定非宿主工作流執行完畢後,才觸發事件。是以這實作了一種等待被調用工作流執行完成才繼續執行的效果。

<b>重要提示:</b>

本執行個體的學習基于WWF中的許多新概念(不包括在以前的教程中),請結合後面的參考資料全面了解。個别難點,請不必過于擔心,我會在後面的系列文章中作細緻的剖析。

      請遵循如下步驟建立一個控制台狀态機工作流示例程式:

1. 啟動VS2008,單擊菜單”檔案“|”建立“|”項目“,建立一個名字為InvokeWorkflowActivityDemo的控制台狀态機工作流示例程式。

2.之後,系統自動打開工作流設計器界面。

3. 從工具箱中拖動四個State活動到工作流設計器中。然後,再依次把兩個StateInitialization活動分别拖動到前兩個State活動中,再拖動一個EventDrivenActivity活動到第三個State活動中。最後,再使用拖動搖桿的方法建立四個State活動的轉換關系,得到如圖所示的情形。

右單擊示例工程,選擇“添加”-“State Machine Workflow...”(如下圖所示),添加一個狀态機工作流,命名為SubWF(見後面的圖)。

在上圖子狀态機設計器中僅拖入一個StateInitialization活動和一個StateFinalization活動,如下圖所示。

右單擊第二個活動,選擇“<b>設定為已完成狀态</b>”選項,使之成為整個子工作流的最終狀态。然後,輕按兩下第一個狀态中的StateInitializationActivity1活動,建立如下圖所示的簡單活動流程。

輕按兩下子活動codeActivity1,輸入以下代碼:

private void codeActivity1_ExecuteCode(object sender, EventArgs e)

{

    Console.WriteLine("這是發自子狀态機中的消息。");

}

在宿主工作流的stateActivity1狀态活動中,添加了一個InvokeWorkflowActivity(輕按兩下stateActivity1狀态活動内部的stateInitializationActivity1,然後拖入一個InvokeWorkflowActivity),如下圖所示。

将InvokeWorkflowActivity1的TargetWorkflow指定為目前項目中前面建立的SubWF工作流,相關設定對話框如下圖所示。

  InvokeWorkflowActivity是放置在StatelnitializationActiv時容器内部的,以便于在進入StateActivity活動時總是最先運作子工作流。

在宿主工作流的stateActivity2内部的EventDrivenActivitv内部放置拖入一個HandleExternalEventActivity。

<b>注意:HandleExternalEventActivity活動用于等待本地服務中的InvokedWorkflowComplete事件觸發,并阻止目前工作流的繼續執行。</b>

對于HandleExternalEventActivity活動, <b>必須設定它的參數InterfaceType和EventName</b>。方法是,單擊屬性視窗中參數InterfaceType右邊的“...”符号,彈出一個對話框如下所示:

從右圖標明我們事先已定義好的接口,單擊“确定”按鈕。

然後,單擊屬性視窗中參數EventName右邊的下拉箭頭,從中選擇已經在標明的接口中聲明的事件(在本例中是InvokedWorkflowComplete)。

WWF中的服務可分為核心服務和本地服務。核心服務由WF定義,而本地服務(也稱為資料交換服務)則是開發人員自定義的。本地服務可以是任何想在WF中實作的服務,一個通常的用處是使用本地服務在工作流執行個體與宿主之間進行通信。有關于“<b>本地服務</b>”的全面讨論是一個複雜的話題,<b>我想在本系列後面的學習教程中對之展開全面深入的探讨</b>,在此不贅述。

根據WWF中本地服務的定義要求,首先要定義一個修飾以ExternalDataExchange屬性的接口,我們對之命名為ILocalService,代碼如下:

[ExternalDataExchange]

internal interface ILocalService

    event EventHandler&lt;ExternalDataEventArgs&gt; InvokedWorkflowComplete;

    void WorkComplete(Guid HostWFGuid);

然後,基于上述接口建立一個本地服務類,代碼如下:

//定義一個本地服務實作,該服務将被添加到工作流運作時引擎中

internal class LocalService : ILocalService

    public event EventHandler&lt;ExternalDataEventArgs&gt; InvokedWorkflowComplete;

    public void WorkComplete(Guid HostWFGuid)//實作接口中聲明的方法

    {

        if (InvokedWorkflowComplete != null)

        {

            InvokedWorkflowComplete(null, new ExternalDataEventArgs(HostWFGuid));

        }

    }

上面定義中,基本遵循了“死”格式,除了方法名稱外。在本文中先不詳細讨論。

根據前面的要求,本地服務負責工作流執行個體與宿主間的通信中介,而加載本地服務的工作是在宿主中完成的。下面給出了宿主部分(program.cs)完整的代碼:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading;

using System.Workflow.Runtime;

using System.Workflow.Runtime.Hosting;

using System.Workflow.Activities;//ExternalDataExehangeService 

namespace InvokeWorkflowActivityDemo

    class Program

        static Guid HostWFGuid;//用于記憶父工作流執行個體的ID标記

        static LocalService ls;

        static void Main(string[] args)

            using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())

            {

                //下面這幾行是必需的死套路

                //加載本地服務

                ExternalDataExchangeService dataService = new ExternalDataExchangeService();

                workflowRuntime.AddService(dataService);

                //将自定義的本地通信服務加載到本地服務中

                ls = new LocalService();

                dataService.AddService(ls);

                //事件初始狀态為終止狀态(此時任何線程可以使用此事件)

                AutoResetEvent waitHandle = new AutoResetEvent(false);

                workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)

                {

                    //如果将要産生僅一個子工作流,那麼需要檢查工作流是否完成,而不是主工作流。

                    if (e.WorkflowInstance.InstanceId != HostWFGuid)

                    {

                        //通過本地服務的特定方法通知主工作流,調用工作流完成

                        ls.WorkComplete(HostWFGuid);

                    }

                    else

                       //此時是主工作流自身,将事件的狀态位置設定為終止狀态,允許一個或多個等待線程繼續。

                        waitHandle.Set();

                };

                workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)

                    Console.WriteLine(e.Exception.Message);

                    waitHandle.Set();

                //啟動父工作流執行個體

                WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(Workflow1));

                HostWFGuid = instance.InstanceId;//記下父工作流執行個體的ID标記

                instance.Start();

                waitHandle.WaitOne();//阻止目前線程,直到目前waitHandle收到信号。

                Console.ReadLine();

            }

按F5運作控制台程式,一般順利的話,将得到如下圖所示運作時快照。

<a href="http://down.51cto.com/data/2354094" target="_blank">附件:http://down.51cto.com/data/2354094</a>

本文轉自朱先忠老師51CTO部落格,原文連結: http://blog.51cto.com/zhuxianzhong/203672,如需轉載請自行聯系原作者

繼續閱讀