大部分企業應用程序都包含開發人員和架構師認為可以通過工作流輕松自然表示的業務流程。從根本上講,工作流是捕捉現實世界中實體間的交互的程序。工作流等待來自外部世界的促進因素,而促進因素卻可能需要相當長的時間才能到來。 作為即將推出的 Microsoft .NET Framework 3.0 的重要組成部分,Windows Workflow Foundation 提供了編程模型和運行時引擎,以便基于安裝了 .NET Framework 2.0 或更高版本的 Window 平臺來構建支持工作流的應用程序,其最低運行要求為 Windows xp Service Pack 2 (SP2) 或 Windows Server 2003。從軟件的角度看,需要人為操作的多數是異步事件處理、狀態保持以及共享服務器可用性。Windows Workflow Foundation 實際上支持任何涉及人為操作的情況。每一個工作流都是一個聲明程序,其中,每條程序語句都用稱為活動的組件表示。關于 Windows Workflow Foundation 的最大誤區之一在于將所有要素活動都看成是順序相連或按狀態機轉換相連。實際上,Windows Workflow Foundation 對執行模型進行了活動自動控制方面的虛擬化。這使您能編寫可以捕捉各種控制流模式的復合活動,范圍包括多種連接和合并、狀態機、圖形、序列、交叉存取和非本地退出等。總之,它將使您能夠通過“高保真”的復合活動對存在于現實世界中的控制流模式進行建模。然而,Windows Workflow Foundation 提供了針對以下兩種模式的內置活動:順序工作流和狀態機工作流。順序工作流有明確的開始和結束點,從始至終,一步接一步,沿著一條可能的線路執行。狀態機工作流可以被表示為一組狀態,每種狀態可能包括各種活動,并由事件觸發。您可以定義初始和完成狀態,并按照所有定義的轉換過程逐個狀態地執行,直至到達結束狀態。正如我所談到的,工作流的構造塊就是活動。構造這樣一個工作流意味著將活動進行組合以創建所需的模型來解決碰到的問題。雖然 Windows Workflow Foundation 提供了很多內置的活動,但依然可以通過自定義活動對其進行完全擴展。了解“開箱即用”活動的目標和功能對于充分理解該平臺的真實潛能十分要害。本期專欄將帶您瀏覽安裝 Windows Workflow Foundation Runtime 和 Visual Studio 2005 Designer 時涉及的標準工作流活動。“開箱即用”活動Windows Workflow Foundation 是 .NET Framework 3.0 (原先稱為 WinFX?)的組成部分。雖然它只是一個測試版本,但我發現最新的 Community Technology PReview(社區技術預覽,CTP)版非常穩定,許多公司正廣泛使用該版本開發應用程序。因此,已經出現大量工具和自定義活動,一個基于新聞組和論壇(如 wf.netfx3.com)的有效的技術支持社區正日益發展壯大。假如您對工作流應用程序感愛好,那么越早熟悉它越好。若要查找最新的下載,請訪問 Windows Workflow Foundation。安裝完畢后,啟動 Visual Studio 2005,打開一個 Visual Basic? 或 C# 工作流項目,查看工具箱中的內容。根據您所選擇的項目類型,工具箱可能如圖 1 中所示的一種。工具箱中的內容與您的選擇操作相關,根據您所選擇的工作流的類型會有不同。非凡是,圖 1 左邊的工具箱還包含您創建狀態機工作流時所需的狀態活動。右邊的工作箱窗口只包含順序工作流的活動。這組預定義的活動可根據目標和預期的行為分為幾類。圖 2 顯示了可能的分類:控制流、執行、事件、Web 服務和狀態機。
圖1 工具箱里的工作流活動(Click the image for a smaller view)
圖2控制流活動治理圖形活動執行的順序。列表列出了實現循環的條件塊以及構造。執行活動包括多種構造,這些構造可終止或掛起工作流、引發異常、執行內部或外部代碼,或者生成另一個工作流。多數工作流需要與主機環境同步 — 通常是 Windows Forms 應用程序或 asp.net 應用程序。事件組中的活動能使工作流停止以等待外部事件、處理接收的事件,或只是在執行下一步之前進行等待。最后,Web 服務和狀態組將目標鎖定在工作流的兩種非凡功能 — 將內部引擎為公開為 Web 服務或公開為狀態機。讓我們檢查一下框架中的主要活動,然后分組進行。通過條件控制工作流 假如在工作流中指定了條件,運行時引擎將對條件進行計算,然后根據計算結果進行操作。兩種基于條件的核心活動是 IfElse 和 Policy。IfElse 活動的執行方式如同高級編程語言中的一條典型的 If 語句。它可以包含任意多基于條件的分支,以及一個在其他條件不滿足情況下執行的默認分支。而 Policy 活動表示一系列規則。在 Windows Workflow Foundation 中,一條規則包括一個條件以及一個或一個以上引發的操作。可以將規則看作 If-Then-Else 語句,其中條件對應 If 塊的 Boolean 臨界條件,操作定義了 Then 和 Else 子句。讓我們進一步了解各個活動,然后對它們進行比較。當被添加到一個工作流中時,IfElse 活動看起如圖 3 所示。默認情況下,它有兩個分支,可以通過右鍵單擊并從上下文菜單中進行選擇來添加新的分支。當運行時引擎達到一個 IfElse 活動,它開始計算從左至右進行的各分支的條件。各分支的條件被確定,第一個計算結果為“true”的分支被運行。您可以通過活動的上下文菜單中的命令往返移動分支以更改分支的計算順序。要啟用分支,需要指定有效的條件。您可以采用以下兩種方法中的一種來指定條件:通過表達式或通過一段代碼。
圖 3IfElse 的實際活動(Click the image for a larger view) 假如您選擇使用表達式來指定條件,則要在設計器設置分支,并為 Visual Studio 2005 的“屬性”框中的“條件”項提供一個公共存放位置。接下來,打開表達式編輯器,輸入一個涉及工作流成員并且其計算值為布爾值的表達式。例如,假如工作流類具有名為 MinimumLength 的公共屬性,您可以將條件設置如下: this.MinimumLength >= 8 圖 4 所示的編輯器完全支持 IntelliSense? 并提供對工作流私有成員和公共成員的訪問。這意味著您也可以調用 Boolean 函數。假設您有一個屬性聲明如下: Public Property MinimumLength() As IntegerGetReturn _minLengthEnd GetSet(ByVal value As Integer)_minLength = valueEnd SetEnd Property
圖 4針對IfElse 活動的Condition Editor(Click the image for a larger view) 當您試圖讀取 MinimumLength 的值時,運行時會結束調用屬性的 get 存取器。該存取器能夠回復私有成員 _minLength 的值。IfElse 活動中的最后分支可以沒有條件。在這種情況下,它將作為 IF 工作流語句的 Else 分支。指定條件的第二種方法是通過臨時代碼。在這種情況下,您可以為工作流類添加方法,例如: Sub EvalCondition(ByVal sender As Object, ByVal e As ConditionalEventArgs)e.Result = ... ' Boolean valueEnd Sub該函數必須與接受對象和 ConditionalEventArgs 類并回復 void 的簽名相匹配。ConditionalEventArgs 類的 Result 成員將設置為布爾值,代表條件的計算結果。IfElse 活動可以進行嵌套以表示復雜的邏輯,但邏輯的設計仍然要在工作流中進行硬編碼。這種方法既有利也有弊。有利的一面在于它使您可以根據您的需求準確設計工作流并將其與其他活動整合。當您需要創建一組規則來初始化部分工作流狀態時,其不利的一面就顯現出來。讓一連串 IfElse 活動僅僅為工作流的內部成員分配值顯然有些矯枉過正。當您真正需要控制工作流的流動并連接各種工作塊時,您應該使用 IfElse 活動組合。假如您所需要的僅僅是一個編程 If 語句序列,帶有附加到分支的簡單代碼,那么最好使用 Policy 活動。Policy 活動是一個規則集合。與各規則相關的代碼僅限于設置工作流屬性,調用工作流方法或針對引用的程序集中的類型的靜態方法。活動與已排序的規則集合相關聯,您可以通過編輯器定義規則。每條規則都有優先級和 Active 屬性。這兩種屬性的組合確定了是否應當評估規則,以及采用哪種優先級。另外,規則還必須指定重估行為 —“Always(始終)”(默認值)或“Never(從不)”。假如設置為“Always”,規則將根據需要進行重估,否則只進行首次評估,以后無論工作流狀態如何變化,也不再更改。然而,作為一個整體設置的規則要進行正向推理。簡而言之,正向推理是指一個規則的操作導致其他相關規則被重估的能力。例如,對另一個規則測試的字段的值進行更新操作需要對所涉及的規則進行重估(除非對該規則的重估被禁用)。正向推理有三種類型。 隱式推理表示運行時引擎將判定哪些字段被一些操作修改了,然后自動對它們進行重估。只要操作顯式地作用于屬性,這種機制即可成功。假如有如下操作,情況又會怎樣: IF this.MinimumLength <= 8 THEN RefreshInternalState()有誰能夠知道 RefreshInternalState 方法將要做什么?該方法可能會觸及涉及策略活動中其他規則的工作流屬性。通過使用方法聲明中的屬性,您可以顯式地表示該方法的行為: <RuleWrite("PassWordLevel")> _Public Sub RefreshInternalState()Me.PasswordLevel = 1End SubRuleWrite 屬性表示方法將要修改指定的屬性;同樣,RuleRead 屬性表示方法將要從指定的屬性中進行讀取。這樣,就可以為運行時引擎提供明確清楚的信息以確保規則設置同步。最后,您可以編寫顯式調用對涉及的屬性進行更新的操作。例如: IF this.MinimumLength <= 8 THEN RefreshInternalState()Update("PasswordLevel")規則操作中的 Update 方法會計劃對包含指定屬性的所有規則進行重估。 QQread.com 推出各大專業服務器評測 linux服務器的安全性能 SUN服務器 HP服務器 DELL服務器 IBM服務器 聯想服務器 浪潮服務器 曙光服務器 同方服務器 華碩服務器 寶德服務器 循環和重復活動 這組活動提供了典型的 While 活動以及 Replicator 活動,這些活動與典型的 For 循環有些共同點。While 活動接受條件并在每次迭代開始時對該條件進行計算。假如條件為“true”,該活動將運行指定的子活動并重復直至條件為“false”。請注重在 While 主體內答應進行單一活動。因此,您可能要使用一個復合活動(如 Sequence 或 Parallel)在循環中執行多個活動。(在此處,使用術語“交錯”可能比“并行”更加準確。因為沒有涉及 Parallel 活動的并發,只有同一線程內的交錯。) 與 Foreach 語句類似,Replicator 活動創建并執行指定的子活動的給定數量的實例。您可以只指定一個子活動,但答應使用復合或自定義活動。您不能通過聲明性屬性來控制迭代數。但是,您可以為初始化事件編寫一個處理程序,并針對各個需要的實例,使用初始化數據填充 CurrentChildData 集合: Sub replicator1_Initialized(ByVal sender As Object, ByVal e As EventArgs)Console.WriteLine("Initializing ...")replicator1.CurrentChildData.Add("You are #1")replicator1.CurrentChildData.Add("You are #2")replicator1.CurrentChildData.Add("You are #3")End Sub前面所述的代碼段規定了 Replicator 的子活動的三個實例的順序,每個實例均使用給定的字符串進行初始化。請注重,假如您將 CurrentChildData 集合置為空,Replicator 將不運行任何子活動,并僅限于觸發頂級事件,如 Initialized 事件和 Completed 事件。您可以使用對象(不一定是字符串)初始化子活動,包括自定義類的實例。Replicator 還包括標示各個子活動初始化和完成的事件。默認情況下,子實例按順序運行,盡管通過設置 ExecutionType 屬性,您可以選擇并行執行。假如需要并行執行,在復制器開始并執行并行線程前,可以創建所有子活動實例。當以順序模式執行時,只有當前一個活動結束時下一個活動才能被實例化。 假如沒有通過 UntilCondition 屬性設置全局條件,Replicator 將在所有復制完成后才結束,否則,將在 UntilCondition 為“true”時終止活動。值得注重的是,盡管在所有子活動已完成并且 UntilCondition 屬性計算為“false”時活動將被掛起,Replicator 也從不通過類似 While 循環中的子活動進行循環。在對活動進行全局實例化后,在每個子活動完成后以及所有包括的活動都已完成后,將對 UntilCondition 進行計算。但是有時,假如條件計算為“true”,Replicator 將立即退出。您可以將 ConditionedActivityGroup (CAG) 活動中的條件執行和循環混合在一起。CAG 包含一些子活動(可能是復合活動),并可運行這些活動,直至滿足全局條件。基本上,CAG 組合了 While 和 IfElse 活動的行為。通過以下偽代碼來表示內部邏輯: While conditionIf child1.WhenCondition Then child1.ExecuteIf child2.WhenCondition Then child2.Execute:If childN.WhenCondition Then childN.ExecuteEnd While每個子活動都有 WhenCondition 屬性。根據對指定條件的計算,可以在當前的迭代中運行或跳過活動。請注重,假如子活動沒有 WhenCondition 集合,子活動將只能在第一次被執行,并在后續的迭代中被跳過。假如需要,可以根據狀態變化的依存關系對所有條件進行計算。在 UntilCondition 返回“true”并立即取消所有當前正在執行的活動后,CAG 活動將終止。假如沒有指定條件,當因為沒有設置條件或者條件計算為“false”而沒有子活動運行時,CAG 也將結束。同步塊涉及交錯活動的順序工作流都會對共享成員的訪問進行系列化。然而,操作是不同的。當兩個或兩個以上以交錯方式運行的序列用到 Parallel 活動時,操作是不同的。請看一下圖 5。While 活動包含兩個序列塊,然后,序列塊又將 Parallel 活動和代碼活動聯系在一起。在內部,Parallel 活動有四個塊,每個塊都對定義為工作流類成員的數字執行數學運算。Parallel 活動的四個分支以交錯方式執行。(每一次在工作流實例中只有一個線程。該線程在 Parallel 活動的分支間往返切換。)跨任務同步又如何呢?默認情況下,子活動內部運行的每一段代碼都進行對共享成員的直接訪問。
圖 7事務與補償活動(Click the image for a larger view) 調用其他代碼此外,還有一些活動可調用和執行代碼。這些活動包括:Code、InvokeWorkflow、InvokeWebService 和 CallExternalMethod。Code 活動最靈活,可以表示您在工作流某一點插入的自定義代碼塊。Code 活動觸發您在工作流中處理的 ExecuteCode 事件,并能使其運行您所需要的代碼。代碼將包含在工作流中并與其一起進行編譯。Code 活動可以調用外部程序集,只要您在 ExecuteCode 事件處理程序中加入所有能夠加載程序集和選擇方法的必要代碼。InvokeWorkflow 活動可以引用工作流和異步調用工作流。您可以傳遞輸入參數,但要注重 InvokeWorkflow 活動要在被啟動的工作流開始執行之前完成。您無法將當前工作流的執行與外部工作流的執行同步,也不能處理當前工作流中的輸出參數。InvokeWebService 活動可以通過代理類同步調用 Web 服務方法。使用 Code 活動并調用 Web 服務,可以對活動的行為進行模擬。最后,CallExternalMethod 活動可用于調用本地服務方法。本地服務是對于實施以 ExternalDataExchange 屬性修飾的接口的工作流可用的任何類。另外,代表本地服務的類必須作為外部數據交換服務添加到工作流運行時。 Dim service As New ExternalDataExchangeService runtime.AddService(service)Dim localService As New YourService()service.AddService(localService)您可以配置 CallExternalMethod 活動以調用由本地服務實施的接口的方法。為什么 CallExternalMethod 僅限于調用已知接口的方法?原因在于活動不僅僅是代碼執行者,而是旨在與 HandleExternalEvent 活動一起實施與本地服務的雙向交流。借助 CallExternalMethod 活動,通過將 HandleExternalEvent 活動加入工作流,您可以調用服務方法,處理服務引發的事件。總結活動是工作流的構造塊。通過在 Visual Studio 2005 設計器中撰寫活動,您可以創建工作流解決方案。與 ASP.NET 中的服務器控件和 Windows Forms 中的控件類似,工作流活動是解決方案的精華所在并形成了開發人員的主要工具箱。Windows Workflow Foundation 提供了一些隨機活動。在此,我要回顧一下涵蓋事務、并行和條件執行、循環以及異常處理的活動。wf.netfx3.com 上提供了解一些其他免費活動。將它們挑出來!