日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Microsoft Windows Workflow Foundation 入門:開發(fā)人員...

 青石水 2010-05-08
Microsoft Windows Workflow Foundation 入門:開發(fā)人員演練
發(fā)布日期 : 11/30/2005 | 更新日期 : 11/30/2005

Dino Esposito
Solid Quality Learning

適用于:
Microsoft Windows Workflow Foundation
Microsoft Windows Vista

摘要:對(duì)于需要為 Microsoft .NET 平臺(tái)創(chuàng)建工作流驅(qū)動(dòng)應(yīng)用程序的開發(fā)人員而言,本文將介紹他們感興趣的 Microsoft Windows Workflow Foundation 技術(shù)和功能。

本文撰寫的對(duì)象為 Windows Workflow Foundation beta 1。請(qǐng)注意,在該技術(shù)的最終版本問(wèn)世之前,內(nèi)容上很可能會(huì)發(fā)生更改。

本頁(yè)內(nèi)容

有關(guān)向 Windows 平臺(tái)添加工作流支持的初步知識(shí)有關(guān)向 Windows 平臺(tái)添加工作流支持的初步知識(shí)
創(chuàng)建第一個(gè)工作流創(chuàng)建第一個(gè)工作流
接收和使用數(shù)據(jù)接收和使用數(shù)據(jù)
工作流運(yùn)行庫(kù) 工作流運(yùn)行庫(kù)
工作流和活動(dòng)工作流和活動(dòng)
開發(fā)自定義活動(dòng)開發(fā)自定義活動(dòng)
計(jì)劃更現(xiàn)實(shí)的工作流計(jì)劃更現(xiàn)實(shí)的工作流
小結(jié)小結(jié)

有關(guān)向 Windows 平臺(tái)添加工作流支持的初步知識(shí)

Microsoft Windows Workflow Foundation (WWF) 是一個(gè)可擴(kuò)展框架,用于在 Windows 平臺(tái)上開發(fā)工作流解決方案。作為即將問(wèn)世的 Microsoft WinFX 的組成部分,Windows Workflow Foundation 同時(shí)提供了 API 和一些工具,用于開發(fā)和執(zhí)行基于工作流的應(yīng)用程序。Windows Workflow Foundation 提供單個(gè)統(tǒng)一的模型,以便創(chuàng)建跨越多個(gè)類別應(yīng)用程序的端到端解決方案,包括人力工作流和系統(tǒng)工作流。

Windows Workflow Foundation 是一個(gè)廣泛且通用的工作流框架,并且從下到上、在每個(gè)級(jí)別都針對(duì)可擴(kuò)展性進(jìn)行了設(shè)計(jì)?;?Windows Workflow Foundation 的解決方案,由得到 Microsoft .NET 代碼支持且在宿主應(yīng)用程序中運(yùn)行的互連組件組成。就像在定制的環(huán)境中以可視方式創(chuàng)建 Web 頁(yè)一樣,您需要在可視設(shè)計(jì)器中制訂特定工作流的步驟,并且添加代碼隱藏工作流組件以實(shí)現(xiàn)規(guī)則并定義業(yè)務(wù)過(guò)程。

Windows Workflow Foundation 提供一個(gè)工作流引擎、一個(gè) .NET 托管 API、運(yùn)行庫(kù)服務(wù)以及與 Microsoft Visual Studio 2005 集成的可視化設(shè)計(jì)器和調(diào)試器??墒褂?Windows Workflow Foundation 來(lái)生成并執(zhí)行同時(shí)跨越客戶端和服務(wù)器的工作流,以及可在所有類型的 .NET 應(yīng)用程序內(nèi)部執(zhí)行的工作流。

本文通過(guò)幾個(gè)循序漸進(jìn)的示例對(duì) Windows Workflow Foundation 的進(jìn)行了流暢的簡(jiǎn)介,并且說(shuō)明它的工作方式。

工作流 是以活動(dòng)示意圖形式定義的人力或系統(tǒng)過(guò)程模型。活動(dòng) 是工作流中的一個(gè)步驟,并且是工作流的執(zhí)行、重用和創(chuàng)作單位?;顒?dòng)示意圖表達(dá)規(guī)則、操作、狀態(tài)以及它們的關(guān)系。Windows Workflow Foundation 工作流通過(guò)安排活動(dòng)而設(shè)計(jì),然后它編譯為 .NET 程序集,且在工作流運(yùn)行庫(kù)和公共語(yǔ)言運(yùn)行庫(kù) (CLR) 中執(zhí)行。

創(chuàng)建第一個(gè)工作流

Windows Workflow Foundation 主要由 .NET 驅(qū)動(dòng)的運(yùn)行庫(kù)環(huán)境組成,該環(huán)境處理在 Visual Studio 設(shè)計(jì)器中設(shè)計(jì)和實(shí)現(xiàn)的特殊對(duì)象。Microsoft .NET Framework 2.0 是支持 Windows Workflow Foundation 所必需的。單獨(dú)的安裝程序包為 Visual Studio 2005 添加了 Windows Workflow Foundation 設(shè)計(jì)器和項(xiàng)目模板支持。一旦安裝,就會(huì)向 Visual Studio 2005 中的標(biāo)準(zhǔn)項(xiàng)目列表中添加一個(gè)全新的節(jié)點(diǎn),如圖 1 所示。

1. Visual Studio 2005 中的工作流項(xiàng)目模板

您可以在各種選項(xiàng)中進(jìn)行選擇,其中每個(gè)選項(xiàng)都標(biāo)識(shí)了特定類型的工作流應(yīng)用程序。表 1 顯示工作流項(xiàng)目模板的不完全列表。

表 1. Visual Studio 2005 中的工作流項(xiàng)目類型

類型

說(shuō)明

順序工作流控制臺(tái)應(yīng)用程序 (Sequential Workflow Console Application)

創(chuàng)建用于生成工作流的項(xiàng)目,該工作流包含一個(gè)默認(rèn)的順序工作流和一個(gè)控制臺(tái)測(cè)試宿主應(yīng)用程序。

順序工作流庫(kù) (Sequential Workflow Library)

創(chuàng)建用于以庫(kù)的形式生成順序工作流的項(xiàng)目。

工作流活動(dòng)庫(kù) (Workflow Activity Library)

創(chuàng)建一個(gè)用來(lái)創(chuàng)建活動(dòng)的庫(kù)的項(xiàng)目,以后可以將其作為工作流應(yīng)用程序中的構(gòu)造塊重用。

狀態(tài)機(jī)控制臺(tái)應(yīng)用程序 (State Machine Console Application)

創(chuàng)建用于生成狀態(tài)機(jī)工作流和控制臺(tái)宿主應(yīng)用程序的項(xiàng)目。

狀態(tài)機(jī)工作流庫(kù) (State Machine Workflow Library)

創(chuàng)建用于以庫(kù)的形式生成狀態(tài)機(jī)工作流的項(xiàng)目。

空工作流 (Empty Workflow)

創(chuàng)建可以包含工作流和活動(dòng)的空項(xiàng)目。

Windows Workflow Foundation 支持兩種基本工作流樣式:順序工作流和狀態(tài)機(jī)工作流。

順序工作流 非常適合以下類型的操作,即該操作由依次執(zhí)行直至最后一個(gè)活動(dòng)完成的步驟的管線表示。但是,順序工作流的執(zhí)行并非完全是順序的。它們?nèi)匀豢梢越邮胀獠渴录蛘邌?dòng)并行任務(wù),在這種情況下,確切的執(zhí)行順序可能有所不同。

狀態(tài)機(jī)工作流 由一組狀態(tài)、轉(zhuǎn)換和操作組成。首先,將一個(gè)狀態(tài)表示為起始狀態(tài),然后,基于事件執(zhí)行向另一個(gè)狀態(tài)的轉(zhuǎn)換。狀態(tài)機(jī)工作流可以具有確定工作流結(jié)束的最終狀態(tài)。

讓我們假設(shè)您選擇并創(chuàng)建了一個(gè)新的順序工作流控制臺(tái)應(yīng)用程序項(xiàng)目。Visual Studio 2005 解決方案資源管理器將包含兩個(gè)文件 — workflow1.cs 以及最初從視圖中隱藏的 workflow1.designer.cs。這兩個(gè)文件表示創(chuàng)建的工作流。Windows Workflow Foundation 工作流包含工作流模型文件和一個(gè)代碼文件類。workflow1.cs 類是可在其中寫入您自己的工作流業(yè)務(wù)邏輯的代碼文件類。workflow1.designer.cs 類表示活動(dòng)示意圖的說(shuō)明。該文件由 Visual Studio 2005 按照與 Microsoft Windows Forms 項(xiàng)目中的窗體非常類似的方式自動(dòng)管理。當(dāng)向工作流中添加活動(dòng)時(shí),Visual Studio 2005 會(huì)用以編程方式生成活動(dòng)示意圖的 Microsoft C# 代碼更新設(shè)計(jì)器類。要繼續(xù)使用 Windows 窗體的類比,那么工作流類似于窗體,而活動(dòng)類似于控件。

我們可以為活動(dòng)布局選擇另一種形式的持久性 — XML 工作流標(biāo)記格式。要嘗試這一方法,可從項(xiàng)目中刪除 workflow1.cs 文件并添加一個(gè)新的工作流項(xiàng),如圖 2 所示。

2. 用代碼分隔添加順序工作流項(xiàng)

現(xiàn)在,項(xiàng)目包含兩個(gè)文件:workflow1.xoml 和 workflow1.xoml.cs。前一個(gè)文件包含表示工作流模型的 XML 工作流標(biāo)記;后一個(gè)文件是一個(gè)代碼文件類,并且包含工作流的源代碼和事件處理程序。如果雙擊 .xoml 文件,會(huì)看到處于運(yùn)行狀態(tài)的可視工作流設(shè)計(jì)器(參見(jiàn)圖 3)。

不存在為工作流模型的序列化選擇標(biāo)記或代碼的運(yùn)行時(shí)暗示 — 一旦該工作流編譯為程序集,它們就是等效的。

工作流應(yīng)用程序是完成工作(例如,發(fā)送或接收數(shù)據(jù))的活動(dòng)和管理一組子活動(dòng)的執(zhí)行的復(fù)合活動(dòng)(例如,IfElseWhile)的混合體。工作流可實(shí)現(xiàn)復(fù)雜的端到端方案,例如文檔審閱、PO 批準(zhǔn)、IT 用戶管理、合作伙伴之間的信息交換、任何種類的向?qū)Щ驑I(yè)務(wù)線應(yīng)用程序。

圖 3 顯示一個(gè)極為簡(jiǎn)單的示例工作流,它只包含一個(gè)活動(dòng) — code1 塊。

3. Visual Studio 2005 工作流設(shè)計(jì)器

Code 塊對(duì)應(yīng)于 Code 類的一個(gè)實(shí)例,并且表示工作流中的一個(gè)活動(dòng),其行為以用戶定義的代碼表示。后端代碼是通過(guò) Visual Studio 2005 輸入的(只需雙擊設(shè)計(jì)器中的所選元素),這是 ASP.NET 應(yīng)用程序和其他 Visual Studio 2005 項(xiàng)目為人熟悉的編程風(fēng)格。

當(dāng)雙擊該活動(dòng)時(shí),代碼文件會(huì)打開且提供代碼處理程序的存根。

private void code1_ExecuteCode(object sender, EventArgs e)
{
// Some code here
}

當(dāng)工作流運(yùn)行庫(kù)在處理工作流的過(guò)程中開始處理指定的活動(dòng)塊時(shí),在代碼處理程序中鍵入的任何語(yǔ)句都將執(zhí)行。以下代碼只是輸出一條歡迎消息。

private void code1_ExecuteCode(object sender, EventArgs e)
{
Code c = (Code) sender;
Console.WriteLine("Hello, from '{0}'.\nI'm an instance of the {1} class.",
c.ID, c.ToString());
}

除了可視化布局以外,工作流還包含 workflow1.xoml.cs 文件中保存的以下代碼。

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
namespace HelloWorldWorkflow
{
public partial class Workflow1 : SequentialWorkflow
{
private void code1_ExecuteCode(object sender, EventArgs e)
{
Code c = (Code) sender;
Console.WriteLine("Hello, from '{0}'.\nI'm an instance of the {1} class.",
c.ID, c.ToString());
}
}
}

partial 屬性涉及不完全類 — 這是 .NET Framework 2.0 中的一個(gè)新概念。不完全類 是這樣的一種類:它的定義可能覆蓋不同的源文件。每個(gè)源文件都包含一個(gè)有頭有尾的普通類定義,只不過(guò)該定義是不完整的,并且沒(méi)有窮盡該類所需的邏輯。編譯器將把不完全的類定義合并到該類可以編譯的完整定義中。不完全類與面向?qū)ο鬀](méi)有任何關(guān)系;它們是用來(lái)擴(kuò)展項(xiàng)目中類行為的源代碼級(jí)別和受到程序集限制的方式。在 .NET Framework 2.0 中,不完全類是用于防止 Visual Studio 2005 在代碼文件內(nèi)部注入自動(dòng)生成代碼的手段。原始類中缺少的任何綁定代碼都將由運(yùn)行庫(kù)通過(guò)添加不完全類進(jìn)行添加。

工作流只能由 Windows Workflow Foundation 工作流運(yùn)行庫(kù)執(zhí)行,并且工作流運(yùn)行庫(kù)需要外部應(yīng)用程序按照若干個(gè)規(guī)則來(lái)承載它。出于測(cè)試目的,Visual Studio 2005 還向項(xiàng)目中添加了一個(gè) program.cs 文件。該文件是一個(gè)簡(jiǎn)單的控制臺(tái)應(yīng)用程序,如下所示。

class Program
{
static AutoResetEvent waitHandle = new AutoResetEvent(false);
static void Main(string[] args)
{
WorkflowRuntime workflowRuntime = new WorkflowRuntime();
workflowRuntime.StartRuntime();
workflowRuntime.WorkflowCompleted += OnWorkflowCompleted;
Type type = typeof(HelloWorldWorkflow.Workflow1);
workflowRuntime.StartWorkflow(type);
waitHandle.WaitOne();
workflowRuntime.StopRuntime();
// A bit of feedback to the user
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("==========================");
Console.WriteLine("Press any key to exit.");
Console.WriteLine("==========================");
Console.ReadLine();
}
static void OnWorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
{
waitHandle.Set();
}
}

正如您在上述代碼中的粗體行中看到的那樣,出于簡(jiǎn)單性的目的,Visual Studio 2005 在該控制臺(tái)應(yīng)用程序中硬編碼工作流類的名稱。要防止控制臺(tái)應(yīng)用程序在完成之后立即退出,您可能需要在 Main 方法的結(jié)尾添加 Console.ReadLine 調(diào)用。此刻,您已經(jīng)做好生成和測(cè)試該工作流的所有準(zhǔn)備:請(qǐng)按 F5 并執(zhí)行。如果一切順利,那么會(huì)看到圖 4 中顯示的輸出。

4. 控制臺(tái)宿主應(yīng)用程序執(zhí)行的示例工作流

調(diào)試工作流應(yīng)用程序也很容易。實(shí)際上,需要做的所有工作就是放置斷點(diǎn)。您可以在工作流代碼文件類中的任何位置放置斷點(diǎn)(就像通常對(duì) C# 代碼所做的那樣),或者直接在設(shè)計(jì)器視圖中放置斷點(diǎn)(這確實(shí)非常有趣)。需要選擇希望調(diào)試器介入的活動(dòng),按 F9 設(shè)置斷點(diǎn),如圖 5 所示。

5. 工作流設(shè)計(jì)器視圖中放置的斷點(diǎn)

一旦代碼流到達(dá)設(shè)置了斷點(diǎn)的活動(dòng),Visual Studio 2005 就會(huì)將控制權(quán)移交給工作流調(diào)試器(參見(jiàn)圖 6)。從這里開始,您可以按照預(yù)期的那樣,在可視化設(shè)計(jì)器中按 F11 單步執(zhí)行代碼和活動(dòng)。

6. 處于調(diào)試會(huì)話狀態(tài)的工作流應(yīng)用程序

接收和使用數(shù)據(jù)

讓我們繼續(xù)分析并修改該工作流,以使其在實(shí)例化以后接收和使用數(shù)據(jù)。有兩種在實(shí)例化工作流以后使其接收數(shù)據(jù)的常規(guī)方法:參數(shù)和事件。如果選擇使用參數(shù),則需要在可視化設(shè)計(jì)器中手動(dòng)定義參數(shù)名稱和類型的列表。如果選擇使用事件,則需要?jiǎng)?chuàng)建并添加一個(gè)自定義活動(dòng)(該活動(dòng)充當(dāng)在工作流模型中的某個(gè)位置介入的外部源),并且傳入一些數(shù)據(jù)。我們將在下文中說(shuō)明基于事件的方法;現(xiàn)在,讓我們重點(diǎn)說(shuō)明一下參數(shù)。

如圖 7 所示,Workflow1 的 Properties 窗格顯示一個(gè) Parameters 集合,您將在設(shè)計(jì)時(shí)用名稱/值對(duì)進(jìn)行填充。

7. 向工作流中添加參數(shù)

圖 8 顯示正在工作的參數(shù)編輯器。您可以為所需的每個(gè)參數(shù)創(chuàng)建一個(gè)新項(xiàng)并指明它的名稱、類型和方向。

8. 添加的 FirstName LastName 字符串參數(shù)

參數(shù)的類型可手動(dòng)鍵入,也可從定制的對(duì)象瀏覽器中選擇。在關(guān)閉 Workflow Parameters Editor 對(duì)話框后,立即修改代碼文件以合并剛剛定義的參數(shù)。您通常添加兩個(gè)公共屬性,并且使它們公開 Parameters 集合的內(nèi)容,如下面的代碼所示。

public partial class Workflow1 : SequentialWorkflow
{
public string UserFirstName
{
get { return (string) Parameters["FirstName"].Value; }
set { Parameters["FirstName"].Value = value; }
}
public string UserLastName
{
get { return (string) Parameters["LastName"].Value; }
set { Parameters["LastName"].Value = value; }
}
:
}

使用公共屬性確實(shí)是一種良好的編程做法,可使代碼變得更加簡(jiǎn)潔明了。它絕不是使用參數(shù)數(shù)據(jù)的要求。直接對(duì)工作流的 Parameters 集合進(jìn)行調(diào)用也是完全可行的。如果用公共屬性包裝參數(shù),則請(qǐng)隨意選擇屬性的名稱。然而,請(qǐng)記住,C# 中的參數(shù)名是區(qū)分大小寫的。

那么是誰(shuí)實(shí)際上通過(guò)這些參數(shù)提供輸入數(shù)據(jù)呢?完成這一任務(wù)的是宿主應(yīng)用程序。然而,需要注意的是,宿主在初始化時(shí)(此時(shí),工作流被加載以便執(zhí)行到運(yùn)行庫(kù)容器中)設(shè)置任何參數(shù)。為了稍微詳細(xì)地說(shuō)明這一點(diǎn),讓我們編寫一個(gè)基于 Windows 窗體的示例宿主應(yīng)用程序。該示例應(yīng)用程序?qū)⑻峁讉€(gè)文本框,以便用戶輸入名字和姓氏(參見(jiàn)圖 9),并且將它們傳遞給工作流代碼處理程序。為了使用這些參數(shù),讓我們重新編寫代碼處理程序,如下所示。

private void code1_ExecuteCode(object sender, EventArgs e)
{
MessageBox.Show("Welcome, " + UserFirstName + " " + UserLastName);
}

該示例 Windows 窗體宿主應(yīng)用程序中的關(guān)鍵內(nèi)容是附加到 Start Workflow 按鈕的單擊處理程序。

9. 工作流宿主 Windows 窗體應(yīng)用程序

窗體的代碼隱藏類的全部源代碼如下所示。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
namespace WinFormHost
{
public partial class Form1 : Form
{
private WorkflowRuntime _wr = null;
private string _workflowAssembly = "";
private string _workflowTypeName = "";
public Form1()
{
InitializeComponent();
_workflowAssembly = "WorkflowWithParams";
_workflowTypeName = "WorkflowWithParams.Workflow1";
_wr = new WorkflowRuntime();
_wr.StartRuntime();
}
private void btnStartWorkflow_Click(object sender, EventArgs e)
{
string assemblyName = _workflowAssembly;
string typeName = _workflowTypeName;
// Attempt to get type by fully-qualified name
Assembly assembly = Assembly.Load(assemblyName);
Type workflowType = assembly.GetType(typeName);
Dictionary parameters = new Dictionary();
parameters.Add("FirstName", txtFirstName.Text);
parameters.Add("LastName", txtLastName.Text);
// Start the workflow
Guid instanceID = Guid.NewGuid();
_wr.StartWorkflow(workflowType, instanceID, parameters);
}
}
}

要填充參數(shù)集合,需要使用由字符串和對(duì)象組成的基于泛型的字典。項(xiàng)的名稱是字符串,而所包含的值被配置為對(duì)象。需要向該字典中添加像工作流模型中的靜態(tài)參數(shù)一樣多的項(xiàng) — 在此情況下,請(qǐng)?zhí)砑?FirstNameLastName。這兩個(gè)參數(shù)獲得在 UI 文本框中鍵入的內(nèi)容。

最后,在創(chuàng)建指定模型的實(shí)例的同時(shí)將執(zhí)行工作流。運(yùn)行庫(kù)對(duì)象上的 StartWorkflow 方法具有多個(gè)重載。代碼中使用的版本接受工作流類型、輸入?yún)?shù)的集合以及系統(tǒng)生成的全局唯一標(biāo)識(shí)符 (GUID)。

對(duì)于每個(gè)進(jìn)程,只需要一個(gè)工作流運(yùn)行庫(kù)實(shí)例;對(duì)于每個(gè) AppDomain,不能有一個(gè)以上的實(shí)例。這里,最需要做的事就是直接在窗體的構(gòu)造函數(shù)中創(chuàng)建所需的實(shí)例。同一個(gè)運(yùn)行庫(kù)對(duì)象可以照看多種工作流實(shí)例。運(yùn)行庫(kù)基于實(shí)例的 GUID 來(lái)區(qū)分它們,并且為每個(gè)特定實(shí)例接收私有數(shù)據(jù)。

10. 正在工作的參數(shù)化工作流(由 Windows 窗體應(yīng)用程序承載)

出于純粹的教學(xué)目的,讓我們?cè)谶@一開發(fā)階段迅速觀察一下設(shè)計(jì)器和工作流標(biāo)記代碼。下面是 workflow1.designer.cs 源代碼文件。

public sealed partial class Workflow1 : SequentialWorkflow
{
private void InitializeComponent()
{
ParameterDeclaration FirstName = new ParameterDeclaration();
ParameterDeclaration LastName = new ParameterDeclaration();
this.code1 = new System.Workflow.Activities.Code();
//
// code1
//
this.code1.ID = "code1";
this.code1.ExecuteCode += new System.EventHandler(this.code1_ExecuteCode);
//
// Workflow1
//
this.Activities.Add(this.code1);
this.DynamicUpdateCondition = null;
this.ID = "Workflow1";
FirstName.Direction = System.Workflow.ComponentModel.ParameterDirection.In;
FirstName.Name = "FirstName";
FirstName.Type = typeof(string);
FirstName.Value = null;
LastName.Direction = System.Workflow.ComponentModel.ParameterDirection.In;
LastName.Name = "LastName";
LastName.Type = typeof(string);
LastName.Value = null;
this.Parameters.Add(FirstName);
this.Parameters.Add(LastName);
}
private Code code1;
}

下面是相應(yīng)的工作流標(biāo)記內(nèi)容。

<?Mapping XmlNamespace="ComponentModel"
ClrNamespace="System.Workflow.ComponentModel"
Assembly="System.Workflow.ComponentModel" ?>
<?Mapping XmlNamespace="Compiler" ClrNamespace="System.Workflow.ComponentModel.Compiler"
Assembly="System.Workflow.ComponentModel" ?>
<?Mapping XmlNamespace="Activities" ClrNamespace="System.Workflow.Activities"
Assembly="System.Workflow.Activities" ?>
<?Mapping XmlNamespace="RuleConditions" ClrNamespace="System.Workflow.Activities.Rules"
Assembly="System.Workflow.Activities.Rules" ?>
<SequentialWorkflow x:Class="WorkflowWithParams.Workflow1"
x:CompileWith="Workflow1.xoml.cs"
ID="Workflow1"
xmlns:x="Definition" xmlns="Activities">
<SequentialWorkflow.Parameters>
<wcm:ParameterDeclaration Name="FirstName" Type="System.String" Direction="In"
xmlns:wcm="ComponentModel" />
<wcm:ParameterDeclaration Name="LastName" Type="System.String" Direction="In"
xmlns:wcm="ComponentModel" />
</SequentialWorkflow.Parameters>
<Code ExecuteCode="code1_ExecuteCode" ID="code1" />
</SequentialWorkflow>

請(qǐng)注意,在創(chuàng)建該工作流的實(shí)例以便執(zhí)行時(shí),必須顯式初始化并傳入 Parameters 集合中靜態(tài)定義的所有參數(shù)。

工作流運(yùn)行庫(kù)

宿主通過(guò) WorkflowRuntime 類與 Windows Workflow Foundation 交互。請(qǐng)不要被如上所示示例宿主表面上的簡(jiǎn)單性所蒙騙,以至于您注意不到這一要點(diǎn)??梢宰屗拗髫?fù)責(zé)處理很多附加、關(guān)鍵的方面,例如:創(chuàng)建一個(gè)或多個(gè)進(jìn)程以及一個(gè)或多個(gè) AppDomain;按照需要封送 AppDomain 之間的調(diào)用;設(shè)置隔離機(jī)制。出于可伸縮性的原因,宿主可能需要?jiǎng)?chuàng)建多個(gè)進(jìn)程來(lái)利用一臺(tái)計(jì)算機(jī)中的多個(gè) CPU,或者在一個(gè)計(jì)算機(jī)場(chǎng)中運(yùn)行大量工作流實(shí)例。

宿主還可以做其他事情。例如,它可以控制在工作流需要長(zhǎng)久等待時(shí)應(yīng)用的策略,偵聽特定事件并將它們傳達(dá)給用戶或管理員,設(shè)置超時(shí)并重試每個(gè)工作流,公開性能計(jì)數(shù)器,以及寫入日志信息以用于調(diào)試和診斷。

主機(jī)通過(guò)在啟動(dòng)時(shí)向容器注冊(cè)的預(yù)定義和自定義服務(wù)來(lái)完成大多數(shù)附加任務(wù)。示例宿主沒(méi)有做上述任何一件事情,并且僅限于啟動(dòng)工作流實(shí)例。這在很多常見(jiàn)情況下是可以接受的。

工作流和活動(dòng)

讓我們后退一步,并且在工作流項(xiàng)目處于活動(dòng)狀態(tài)時(shí)分析一下 Visual Studio 2005 工具箱。圖 11 中顯示的工具箱列出了可用來(lái)設(shè)計(jì)步驟的順序及其相互關(guān)系,以便形成工作流模型的活動(dòng)。

圖 11. Windows Workflow Foundation 工作流的構(gòu)造塊

表 2 提供每個(gè)活動(dòng)的簡(jiǎn)短說(shuō)明,以及這些活動(dòng)適用于哪些方案。

表 2. Windows Workflow Foundation 構(gòu)造塊

活動(dòng)

說(shuō)明

Code

使您能夠向工作流中添加 Microsoft Visual Basic .NET 或 C# 代碼以執(zhí)行自定義操作。但是,這些代碼不應(yīng)該用對(duì) Web 服務(wù)等外部資源的依賴性來(lái)阻塞工作流。

Compensate

使您能夠在發(fā)生錯(cuò)誤時(shí)調(diào)用代碼來(lái)撤消或者補(bǔ)償已經(jīng)由工作流執(zhí)行的操作。通常,對(duì)于現(xiàn)在已被取消的操作,您可能希望向先前已經(jīng)獲得成功通知的用戶發(fā)送電子郵件。

ConditionedActivityGroup (CAG)

使您的工作流能夠基于特定于每個(gè)活動(dòng)的準(zhǔn)則有條件地執(zhí)行一組子活動(dòng),直到針對(duì) CAG 整體滿足完成條件。子活動(dòng)相互獨(dú)立并可能并行執(zhí)行。

Delay

使您能夠控制工作流的定時(shí)以及將延遲內(nèi)置到工作流。您可以在 Delay 活動(dòng)上提供超時(shí),以便工作流在恢復(fù)執(zhí)行之前暫停。

EventDriven

代表一系列其執(zhí)行由事件觸發(fā)的活動(dòng)。第一個(gè)子活動(dòng)必須能夠等待外部事件??尚械氖滓踊顒?dòng)是 EventSink 和 Delay。在這種情況下,Delay 用作超時(shí)。

EventSink

在向 WorkflowRuntime 注冊(cè)的數(shù)據(jù)交換服務(wù)引發(fā)指定事件時(shí),使工作流能夠從該服務(wù)接收數(shù)據(jù)。

ExceptionHandler

使您能夠處理指定類型的異常。ExceptionHandler 活動(dòng)是其他活動(dòng)的包裝,在指定的異常發(fā)生時(shí),這些活動(dòng)實(shí)際執(zhí)行所需的任何工作。可根據(jù)情況指定一個(gè)用于存儲(chǔ)異常的本地變量,并且使其可以在代碼隱藏中使用。

IfElse

使您的工作流能夠有條件地執(zhí)行多個(gè)可供選擇的分支之一。可在每個(gè)分支上放置一個(gè)條件,而條件為真的第一個(gè)分支將執(zhí)行。無(wú)需在最后一個(gè)分支上放置條件,因?yàn)樗灰暈?#8220;else”分支。

InvokeMethod

使您的工作流能夠調(diào)用接口上的方法,以便將消息從工作流發(fā)送到向 WorkflowRuntime 注冊(cè)的數(shù)據(jù)交換服務(wù)。

InvokeWebService

使您的工作流能夠調(diào)用 Web 服務(wù)方法。您需要指定要使用的代理類(使用 WSDL),以及您想要調(diào)用的方法的名稱。同步和異步調(diào)用都受到支持。

InvokeWorkflow

使您的工作流能夠調(diào)用或啟動(dòng)另一個(gè)工作流(可達(dá)到任意深度)。例如,被調(diào)用的工作流可以調(diào)用第三個(gè)工作流,該工作流又可以調(diào)用第四個(gè)工作流,等等。遞歸調(diào)用不受支持。受支持的調(diào)用模型是發(fā)后不理。

Listen

使工作流能夠等待(可能存在的)多個(gè)事件之一,或者在指定的超時(shí)間隔之后停止等待,并且基于結(jié)果分支??上蛎總€(gè)分支中添加一個(gè)或多個(gè)由事件驅(qū)動(dòng)的活動(dòng)。只有第一個(gè)滿足條件的分支被執(zhí)行;其他分支都不會(huì)運(yùn)行。

Parallel

使您的工作流能夠相互獨(dú)立地執(zhí)行兩個(gè)或更多個(gè)操作。該活動(dòng)在繼續(xù)執(zhí)行之前會(huì)等待這些操作終止。

Policy

使您能夠表示或執(zhí)行規(guī)則集合。該活動(dòng)不在工具箱中;要訪問(wèn)它的功能,必須創(chuàng)建自定義活動(dòng)并使用派生。

Replicator

使您的工作流能夠創(chuàng)建給定活動(dòng)的任意多個(gè)實(shí)例,并且順序或同時(shí)執(zhí)行它們。

SelectData

使您的工作流能夠通過(guò)在外部數(shù)據(jù)源對(duì)象上定義的方法查詢外部數(shù)據(jù)。當(dāng)觸發(fā) SelectData 活動(dòng)時(shí),關(guān)聯(lián)的方法將在宿主線程內(nèi)部執(zhí)行。該方法返回的值被傳遞給工作流。

Sequence

使您能夠協(xié)調(diào)一組子活動(dòng)的連續(xù)執(zhí)行。該序列在最后一個(gè)子活動(dòng)完成之后完成。

SetState

使您的狀態(tài)機(jī)工作流能夠指定向新狀態(tài)的轉(zhuǎn)換。

State

表示狀態(tài)機(jī)工作流中的狀態(tài)。

StateInitialization

在 State 活動(dòng)中,用作在狀態(tài)轉(zhuǎn)換時(shí)執(zhí)行的子活動(dòng)的容器。

Suspend

掛起工作流的操作,以便能夠在發(fā)生某個(gè)錯(cuò)誤條件時(shí)進(jìn)行干預(yù)。當(dāng)工作流實(shí)例掛起時(shí),將記錄錯(cuò)誤??芍付ㄒ粋€(gè)消息字符串來(lái)幫助管理員診斷發(fā)生了什么事情。與當(dāng)前實(shí)例關(guān)聯(lián)的所有狀態(tài)信息都被保存,并且這些信息會(huì)在管理員繼續(xù)執(zhí)行時(shí)恢復(fù)。

Terminate

使您能夠在發(fā)生任何異常情況時(shí)立即結(jié)束工作流的操作。如果是在 Parallel 活動(dòng)內(nèi)部調(diào)用,則所有分支都被突然終止,而無(wú)論它們的當(dāng)前狀態(tài)如何。當(dāng)工作流終止時(shí),會(huì)記錄錯(cuò)誤,并提供一個(gè)消息以幫助管理員弄清楚發(fā)生了什么事情。

Throw

使您能夠引發(fā)指定類型的異常。使用該活動(dòng)等效于在用戶代碼中引發(fā)異常的代碼處理程序。該活動(dòng)是引發(fā) .NET 異常的聲明性方式。

TransactionalContext

事務(wù)上下文 是用于對(duì)活動(dòng)進(jìn)行分組的塊。該活動(dòng)主要用于事務(wù)性執(zhí)行、補(bǔ)償和異常處理,可以根據(jù)情況進(jìn)行同步。通過(guò)同步事務(wù)性上下文,可確保對(duì)活動(dòng)中共享數(shù)據(jù)的任何訪問(wèn)都將正確地序列化。

UpdateData

使您的工作流能夠通過(guò)在外部數(shù)據(jù)源對(duì)象上定義的方法更新數(shù)據(jù)存儲(chǔ)區(qū)。當(dāng) UpdateData 活動(dòng)被觸發(fā)時(shí),關(guān)聯(lián)的方法將在宿主線程內(nèi)部執(zhí)行。

WaitForData

使您的工作流能夠從外部數(shù)據(jù)源對(duì)象接收信息。當(dāng)傳入的數(shù)據(jù)修改綁定數(shù)據(jù)源的狀態(tài)時(shí),該活動(dòng)被觸發(fā)。傳入的數(shù)據(jù)是通過(guò)綁定數(shù)據(jù)源服務(wù)接收的。

WaitForQuery

使外部應(yīng)用程序能夠在您的工作流中查詢數(shù)據(jù)。該活動(dòng)將在從宿主收到查詢之前一直等待。來(lái)自外部應(yīng)用程序的查詢使用綁定數(shù)據(jù)源服務(wù)上的方法提交給工作流。

WebServiceReceive

使作為 Web 服務(wù)本身公開的工作流能夠接收 Web 服務(wù)請(qǐng)求。

WebServiceResponse

使作為 Web 服務(wù)本身公開的工作流能夠響應(yīng) Web 服務(wù)請(qǐng)求。

While

使您的工作流能夠在一個(gè)條件被滿足時(shí)執(zhí)行一個(gè)或多個(gè)活動(dòng)。在每次迭代之前,都評(píng)估該條件。如果為真,則所有子活動(dòng)都會(huì)執(zhí)行;否則,該活動(dòng)完成。可指定聲明性條件或代碼條件。

活動(dòng)表示使用 Windows Workflow Foundation 進(jìn)行工作流編程的聲明性方法。使用活動(dòng),可在設(shè)計(jì)時(shí)創(chuàng)作工作流模型并將值分配給每個(gè)活動(dòng)的屬性。如果選擇帶有代碼分隔功能的工作流項(xiàng),則最后的結(jié)果會(huì)作為 XML 標(biāo)記保存到具有 .xoml 擴(kuò)展名的工作流標(biāo)記文件中。否則,創(chuàng)作的模型將作為對(duì)工作流對(duì)象模型的一系列調(diào)用持久保存在設(shè)計(jì)器生成的 C# 或 Visual Basic .NET 類文件中。前一種方法類似于 ASP.NET 頁(yè),而后一種方法類似于 Windows 窗體應(yīng)用程序所采用的方法。

Visual Studio 2005 隱藏了這兩種方法之間的大多數(shù)差異。您總是以可視方式設(shè)計(jì)工作流,并且 Visual Studio 2005 透明地將您的工作持久保存為兩種不同格式中的一種。如果您選擇采用“僅代碼”解決方案(沒(méi)有 XOML 和代碼分隔),則可調(diào)整設(shè)計(jì)器代碼以使其變得更加靈活一些。例如,可讓它從配置文件或數(shù)據(jù)庫(kù)中讀取參數(shù)的默認(rèn)值。如果選擇采用工作流標(biāo)記和代碼分隔,則在工作流的代碼及其模型之間產(chǎn)生巧妙的分隔。

是否可以用編程方式修改工作流模型?在設(shè)計(jì)時(shí),可在 Visual Studio 中以編程方式對(duì)工作流做您可以做的所有事情。在運(yùn)行時(shí),對(duì)活動(dòng)集合進(jìn)行動(dòng)態(tài)更新也是可以的,而這為您提供了對(duì)正在運(yùn)行的工作流實(shí)例進(jìn)行更改的能力。動(dòng)態(tài)更改由在設(shè)計(jì)時(shí)未知的業(yè)務(wù)更改激發(fā),或由首先修改然后完成業(yè)務(wù)過(guò)程的業(yè)務(wù)邏輯需要激發(fā)。在任何情況下,它都應(yīng)該只涉及有限的更改 — 完善而不是重新設(shè)計(jì)。

動(dòng)態(tài)更新適用于應(yīng)用程序上下文中的單個(gè)工作流實(shí)例。同一工作流類型的將來(lái)實(shí)例將不會(huì)受到更改的影響。對(duì)工作流實(shí)例的動(dòng)態(tài)更新可以從工作流實(shí)例本身中進(jìn)行,也可以從您的應(yīng)用程序代碼外部進(jìn)行。

Windows Workflow Foundation 框架支持 Web 服務(wù)互操作性,這包括能夠?qū)⒐ぷ髁髯鳛?Web 服務(wù)向 ASP.NET 客戶端和其他工作流公開。Windows Workflow Foundation 支持將工作流作為在 Microsoft IIS 6.0 上運(yùn)行 ASP.NET 的 Web 服務(wù)器或服務(wù)器場(chǎng)上的 ASP.NET Web 服務(wù)公開。

Windows Workflow Foundation 框架活動(dòng)集包含 WebServiceReceiveWebServiceResponse 活動(dòng),這使工作流能用作 Web 服務(wù)終結(jié)點(diǎn)。

要想作為 Web 服務(wù)公開,工作流必須包含 WebServiceReceive 活動(dòng),以便從客戶端獲得傳入的調(diào)用。快捷菜單命令將工作流作為 Web 服務(wù)發(fā)布,如圖 12 所示。

圖 12. 將工作流作為 Web 服務(wù)發(fā)布

開發(fā)自定義活動(dòng)

Windows Workflow Foundation 中可擴(kuò)展性的要點(diǎn)是創(chuàng)建自定義活動(dòng),因?yàn)檫@使您可以擴(kuò)展用于生成工作流模型的構(gòu)造塊集。

讓我們研究一下活動(dòng)的內(nèi)部體系結(jié)構(gòu),方法是開發(fā)一個(gè)自定義活動(dòng)來(lái)發(fā)送電子郵件。Windows Workflow Foundation 為自定義活動(dòng)提供一個(gè)現(xiàn)成的 Visual Studio 2005 模板。它的名稱為 Workflow Activity Library。該模板創(chuàng)建一個(gè)可任意重命名的 C# 文件 — 例如,可將其重命名為 SendMailActivity?;顒?dòng)是從父類繼承的普通類??蓮娜魏维F(xiàn)有活動(dòng)(無(wú)論它是內(nèi)置的活動(dòng),還是您自己創(chuàng)建或從第三方供應(yīng)商購(gòu)買的活動(dòng))派生您的活動(dòng)。顯然,父類向新的組件中添加了預(yù)定義的行為。要完全從頭開始生成活動(dòng),請(qǐng)讓其從 Activity 派生。下面的代碼示例顯示新類的主干。

public partial class SendMailActivity : System.Workflow.ComponentModel.Activity
{
public SendMailActivity()
{
InitializeComponent();
}
protected override Status Execute(ActivityExecutionContext context)
{
:
}
}

正如您可以猜到的那樣,Execute 方法是該組件的核心 — 即完成該組件的核心任務(wù)的位置。

在開發(fā)之后,活動(dòng)就被放到工具箱中,以供拖放操作將其拖放到新的工作流應(yīng)用程序中。盡管屬性列表不是必需的,但不帶屬性的活動(dòng)幾乎沒(méi)有任何用處。要添加屬性,您需要在設(shè)計(jì)器中選擇正在開發(fā)的活動(dòng),然后單擊 Properties 窗格上的 Activity Properties 項(xiàng)(參見(jiàn)圖 13)。

圖 13. 向自定義活動(dòng)中添加屬性

向活動(dòng)中添加屬性與向工作流中添加參數(shù)并無(wú)太大的不同。必須做的工作就是為每個(gè)需要的屬性配置名稱和屬性。圖 14 顯示如何向 SendMail 活動(dòng)中添加 To 屬性。

圖 14. 添加到 SendMail 活動(dòng)中的 To 屬性

為了完成所有工作,我們添加了其他屬性(如 From、SubjectBodyHost),以便用戶可以完整地配置要發(fā)送的電子郵件。當(dāng)您添加屬性時(shí),向?qū)?huì)修改包含活動(dòng)的邏輯在內(nèi)的 C# 代碼隱藏文件。

最后一個(gè)步驟是使 Execute 方法變得充實(shí)一些,以指示它在執(zhí)行該活動(dòng)時(shí)發(fā)送電子郵件。

protected override Status Execute(ActivityExecutionContext context)
{
MailAddress toAddress = new MailAddress(To);
MailAddress fromAddress = new MailAddress(From);
MailAddressCollection addresses = new MailAddressCollection();
addresses.Add(toAddress);
MailMessage msg = new MailMessage(fromAddress, toAddress);
msg.Subject = Subject;
msg.Body = Body;
SmtpClient mail = new SmtpClient(Host);
mail.Send(msg);
return Status.Closed;
}

如果在工作流解決方案的內(nèi)部開發(fā)活動(dòng)項(xiàng)目,則工作流文檔將自動(dòng)查找工具箱中列出的新活動(dòng),如圖 15 所示。否則,必須通過(guò)右鍵單擊工具箱來(lái)添加它。

圖 15. SendMail 活動(dòng)顯示在工具箱中

圖 16 說(shuō)明 SendMail 活動(dòng)確實(shí)有效。

圖 16. 正在工作的 SendMail 活動(dòng)

計(jì)劃更現(xiàn)實(shí)的工作流

讓我們看一下如何組合表 2 中列出的一些活動(dòng),從而解決一項(xiàng)更為現(xiàn)實(shí)的任務(wù)。假設(shè)有這樣一個(gè)業(yè)務(wù)應(yīng)用程序,其中,訂單在完成之前可能要經(jīng)歷多個(gè)狀態(tài)。在典型的方案中,有一些根據(jù)當(dāng)前狀態(tài)指示訂單中可能發(fā)生某些事件的規(guī)則。例如,可以處理或更新未完成的訂單,但不能將其取消或發(fā)送。

當(dāng)事件發(fā)生時(shí),狀態(tài)機(jī)工作流將轉(zhuǎn)換訂單的狀態(tài)。例如,當(dāng)訂單未完成并且 BeingProcessed 事件發(fā)生時(shí),狀態(tài)機(jī)工作流會(huì)將訂單轉(zhuǎn)換到正確的狀態(tài)。圖 17 顯示示例訂單狀態(tài)機(jī)工作流的關(guān)系圖。

圖 17. 管理訂單的狀態(tài)機(jī)的示例架構(gòu)

讓我們首先創(chuàng)建一個(gè)狀態(tài)機(jī)工作流。您將使用 State 活動(dòng)對(duì)訂單的可能狀態(tài)進(jìn)行建模。然后,通過(guò)使用 EventDriven 活動(dòng)指定可以從每個(gè)狀態(tài)發(fā)生的事件。通過(guò)自定義服務(wù)產(chǎn)生的外部事件將轉(zhuǎn)換訂單的狀態(tài)。要執(zhí)行轉(zhuǎn)換,需要使用 SetState 活動(dòng)。創(chuàng)作工作流后,需要使用 Windows 窗體宿主應(yīng)用程序來(lái)檢驗(yàn)它。

工作流通過(guò)專門為此目的建立的服務(wù)與外部世界通信。該服務(wù)會(huì)引發(fā)工作流內(nèi)的事件驅(qū)動(dòng)活動(dòng)將掛鉤到的事件。同樣,該服務(wù)公開了供該工作流調(diào)用的公共方法并向主機(jī)發(fā)送數(shù)據(jù)。方法和事件在接口中定義。該接口也稱為數(shù)據(jù)交換服務(wù)。每當(dāng)工作流與外部組件交互(進(jìn)行輸入和輸出)時(shí),您都需要該服務(wù)。

數(shù)據(jù)交換服務(wù)是常規(guī)的 .NET 類庫(kù),它最起碼包含一個(gè)接口定義以及一個(gè)實(shí)現(xiàn)該接口的類。該接口是為您希望表示的任務(wù)定制的。在此情況下,狀態(tài)機(jī)表示訂單的生存期,該接口包含五個(gè)事件。

[DataExchangeService]
public interface IOrderService
{
event EventHandler OrderCreated;
event EventHandler OrderShipped;
event EventHandler OrderUpdated;
event EventHandler OrderProcessed;
event EventHandler OrderCanceled;
}

[DataExchangeService] 屬性將 IOrderService 標(biāo)記為數(shù)據(jù)交換服務(wù)接口,以便工作流運(yùn)行庫(kù)知道它將用來(lái)與工作流實(shí)例交換數(shù)據(jù)。在此情況下,宿主將向一串 EventDriven 活動(dòng)引發(fā)事件,從而向工作流實(shí)例發(fā)送數(shù)據(jù)。如果需要,可通過(guò) InvokeMethod 活動(dòng)從工作流實(shí)例內(nèi)部調(diào)用 IOrderService 接口中的方法。

該接口中的事件聲明使用泛型,這是 .NET Framework 2.0 中的一項(xiàng)非常熱門的新功能。EventHandler 類是一個(gè)委托,它表示用于處理事件的函數(shù)的原型。在 .NET Framework 1.x 中,EventHandler 按如下方式定義。

void EventHandler(object sender, EventArgs e)

要使該事件傳遞自定義數(shù)據(jù)結(jié)構(gòu)(例如,OrderEventArgs),必須創(chuàng)建一個(gè)新的委托并使用它來(lái)替代 EventHandler。下面是一個(gè)示例。

delegate void OrderEventHandler(object sender, OrderEventArgs e)

該模式在 .NET Framework 2.0 中仍然有效。然而,.NET Framework 2.0 中泛型的出現(xiàn)使您無(wú)需顯式定義(和實(shí)例化)新的委托類即可獲得相同的結(jié)果。您將使用 EventHandler 委托的泛型版本,其中,事件數(shù)據(jù)的類型是參數(shù)。

事件傳遞 OrderEventArgs 類型的客戶端數(shù)據(jù),該類型是一個(gè)從 Windows Workflow Foundation WorkflowMessageEventArgs 類派生的自定義類,后者在同一個(gè)程序集中按如下方式定義。

[Serializable]
public class OrderEventArgs : WorkflowMessageEventArgs
{
private string _orderId;
public OrderEventArgs(Guid instanceId, string orderId) : base(instanceId)
{
_orderId = orderId;
}
public string OrderId
{
get { return _orderId; }
set { _orderId = value; }
}
}

下一步,需要定義一個(gè)實(shí)現(xiàn)該接口的類。該類所引發(fā)的公共方法與接口中引發(fā)的事件一樣多。

public class OrderService : IOrderService
{
public OrderService()
{
}
public void RaiseOrderCreatedEvent(string orderId, Guid instanceId)
{
if (OrderCreated != null)
OrderCreated(null, new OrderEventArgs(instanceId, orderId));
}
public void RaiseOrderShippedEvent(string orderId, Guid instanceId)
{
if (OrderShipped != null)
OrderShipped(null, new OrderEventArgs(instanceId, orderId));
}
public void RaiseOrderUpdatedEvent(string orderId, Guid instanceId)
{
if (OrderUpdated != null)
OrderUpdated(null, new OrderEventArgs(instanceId, orderId));
}
public void RaiseOrderProcessedEvent(string orderId, Guid instanceId)
{
if (OrderProcessed != null)
OrderProcessed(null, new OrderEventArgs(instanceId, orderId));
}
public void RaiseOrderCanceledEvent(string orderId, Guid instanceId)
{
if (OrderCanceled != null)
OrderCanceled(null, new OrderEventArgs(instanceId, orderId));
}
public event EventHandler OrderCreated;
public event EventHandler OrderShipped;
public event EventHandler OrderUpdated;
public event EventHandler OrderProcessed;
public event EventHandler OrderCanceled;
}

現(xiàn)在,需要用訂單服務(wù)編譯該程序集,并重新切換到狀態(tài)機(jī)工作流項(xiàng)目。在該工作流項(xiàng)目中,首先需要添加對(duì)新創(chuàng)建程序集的引用。接下來(lái),需要添加四個(gè) State 活動(dòng)并且按如下方式命名它們: WaitingForOrderState、OrderOpenState、OrderProcessedStateOrderCompletedState。

表 3 表示工作流的狀態(tài)關(guān)系圖。每個(gè)狀態(tài)都有一些能夠?qū)е孪蛄硪粋€(gè)狀態(tài)進(jìn)行轉(zhuǎn)換的事件。

表 3. 訂單的示例狀態(tài)機(jī)

狀態(tài)

受支持的事件

轉(zhuǎn)換到

WaitingForOrderState

OrderCreated

OrderOpenState

OrderOpenState

OrderUpdated

OrderOpenState

 

OrderProcessed

OrderProcessedState

OrderProcessedState

OrderUpdated

OrderOpenState

 

OrderCanceled

Terminate 活動(dòng)

 

OrderShipped

OrderCompletedState

OrderCompletedState

   

要實(shí)現(xiàn)該關(guān)系圖,需要向每個(gè) State 活動(dòng)中添加與該表中受支持事件相同數(shù)目的 EventDriven 塊。例如,名為 WaitingForOrderStateState 活動(dòng)將包含單個(gè) EventDriven 活動(dòng)(該活動(dòng)的名稱可以是任意的,例如 OrderCreatedEvent)。如圖 18 所示,EventDriven 活動(dòng)嵌入一個(gè) EventSink 活動(dòng)和一個(gè) SetState 活動(dòng),以便捕獲外部事件并轉(zhuǎn)換到新的狀態(tài)。

圖 18. OrderCreatedEvent EventDriven 活動(dòng)的內(nèi)部視圖

EventSink 活動(dòng)的 Properties 窗格上,可選擇自己喜歡的數(shù)據(jù)交換服務(wù)(在此情況下為 IOrderService 接口)以及要預(yù)訂的事件名稱。如果單擊 EventSink 活動(dòng) Properties 窗格上的 InterfaceType 項(xiàng),則 Visual Studio 2005 將提供該項(xiàng)目可用的數(shù)據(jù)交換服務(wù)列表。選擇服務(wù)后,EventName 屬性反映由該服務(wù)所公開事件的列表。可選擇自己感興趣的事件并繼續(xù)。對(duì)于 OrderCreatedEvent 活動(dòng),可選擇 OrderCreated 事件。

SetState 活動(dòng)將狀態(tài)機(jī)轉(zhuǎn)換到由其 TargetState 屬性指示的新狀態(tài)。圖 18 中的 SetState 活動(dòng)設(shè)置為 OrderOpenState。

可對(duì)表 3 中的所有狀態(tài)和事件接收器重復(fù)執(zhí)行上述操作。最后,您的工作流應(yīng)該如圖 19 所示。

圖 19. 最終完成的訂單狀態(tài)機(jī)

最后一個(gè)步驟涉及到生成 Windows 窗體應(yīng)用程序以測(cè)試該工作流。用戶界面包含一個(gè)用于跟蹤所有未完成訂單的列表視圖,以及用于創(chuàng)建新訂單的文本框和按鈕。其他按鈕將用來(lái)更新、處理和終止該訂單。

狀態(tài)機(jī)工作流在 Form_Load 事件中初始化。狀態(tài)機(jī)工作流的初始化要比順序工作流復(fù)雜一些,尤其是當(dāng)您希望能夠跟蹤狀態(tài)更改的時(shí)候。下面的代碼示例顯示如何初始化工作流運(yùn)行庫(kù)。

private void StartWorkflowRuntime()
{
// Create a new Workflow Runtime for this application
_runtime = new WorkflowRuntime();
// Register event handlers for the WorkflowRuntime object
_runtime.WorkflowTerminated += new
EventHandler(WorkflowRuntime_WorkflowTerminated);
_runtime.WorkflowCompleted += new
EventHandler(WorkflowRuntime_WorkflowCompleted);
// Create a new instance of the StateMachineTrackingService class
_stateMachineTrackingService = new StateMachineTrackingService(_runtime);
// Start the workflow runtime
_runtime.StartRuntime();
// Add a new instance of the OrderService to the runtime
_orderService = new OrderService();
_runtime.AddService(_orderService);
}

StateMachineTrackingService 在運(yùn)行庫(kù)之上工作,并且用跟蹤工作流中狀態(tài)更改的功能來(lái)擴(kuò)展它。數(shù)據(jù)交換服務(wù)的實(shí)例還被添加到運(yùn)行庫(kù)中。

當(dāng)用戶單擊以創(chuàng)建新訂單時(shí),將執(zhí)行下面的代碼。

private Guid StartOrderWorkflow(string orderID)
{
// Create a new GUID for the WorkflowInstanceId
Guid instanceID = Guid.NewGuid();
// Load the OrderWorkflows assembly
Assembly asm = Assembly.Load("OrderWorkflows");
// Get a type reference to the OrderWorkflows.Workflow1 class
Type workflowType = asm.GetType("OrderWorkflows.Workflow1");
// Start a new instance of the state machine with state tracking support
StateMachineInstance stateMachine =
_stateMachineTrackingService.RegisterInstance(workflowType, instanceID);
stateMachine.StateChanged += new
EventHandler(StateMachine_StateChanged);
stateMachine.StartWorkflow();
_stateMachineInstances.Add(instanceID.ToString(), stateMachine);
// Return the workflow GUID
return instanceID;
}

首先,代碼實(shí)例化工作流實(shí)例并注冊(cè)狀態(tài)更改的事件處理程序。請(qǐng)注意,使用 .NET Reflection 來(lái)獲得類型信息并不是絕對(duì)需要的,但這可以大大提高靈活性。普通的舊運(yùn)算符 typeof 也可以很好地將工作流實(shí)例的類型傳遞給工作流運(yùn)行庫(kù)。

圖 20 顯示正在工作的示例應(yīng)用程序。按鈕是基于所選工作流實(shí)例的狀態(tài)而啟用的。

圖 20. Windows 窗體應(yīng)用程序中承載的狀態(tài)機(jī)工作流

當(dāng)用戶單擊給定按鈕時(shí),通信接口上的相應(yīng)事件將被引發(fā)并被工作流的事件接收器捕獲。例如,對(duì)處于掛起狀態(tài)的工作流實(shí)例而言,其 Order Processed 按鈕的單擊事件將按如下方式處理。

private void btnOrderEvent_Click(object sender, EventArgs e)
{
// Get the name of the clicked button
string buttonName = ((Button)sender).Name;
// Get the GUID of the selected order
Guid instanceID = GetSelectedWorkflowInstanceID();
// Get the ID of the selected order
string orderID = GetSelectedOrderID();
// Disable buttons before proceeding
DisableButtons();
// Determines what to do based on the name of the clicked button
switch(buttonName)
{
// Raise an OrderShipped event using the Order Local Service
case "btnOrderShipped":
_orderService.RaiseOrderShippedEvent(orderID, instanceID);
break;
// Raise an OrderUpdated event using the Order Local Service
case "btnOrderUpdated":
_orderService.RaiseOrderUpdatedEvent(orderID, instanceID);
break;
// Raise an OrderCanceled event using the Order Local Service
case "btnOrderCanceled":
_orderService.RaiseOrderCanceledEvent(orderID, instanceID);
break;
// Raise an OrderProcessed event using the Order Local Service
case "btnOrderProcessed":
_orderService.RaiseOrderProcessedEvent(orderID, instanceID);
break;
}
}

該工作流中引發(fā)的事件由圖 21 中所示的 EventDriven 活動(dòng)捕獲。

圖 21. 狀態(tài)機(jī)用于處理 Order Processed 事件的 EventDriven 塊

EventSink 活動(dòng)捕獲該事件,并且通過(guò)轉(zhuǎn)換到 SetState 活動(dòng)所設(shè)置的狀態(tài)來(lái)處理它。工作流中的狀態(tài)更改由附加的狀態(tài)跟蹤服務(wù)檢測(cè),并通過(guò) StateChanged 事件報(bào)告給宿主,如上述代碼清單所示。

您可以在 http://msdn.microsoft.com/workflow 找到本文中討論的全部示例的完整源代碼,以及更多的工作流內(nèi)容。

小結(jié)

Windows Workflow Foundation 旨在成為新的和現(xiàn)有的 Microsoft 產(chǎn)品的工作流框架,它向所有需要為 .NET 平臺(tái)創(chuàng)建工作流驅(qū)動(dòng)應(yīng)用程序的開發(fā)人員提供了 WinFX 的強(qiáng)大功能和 Visual Studio 2005 的易用性。

Windows Workflow Foundation 為工作臺(tái)帶來(lái)的主要好處是統(tǒng)一的工作流模型和一組能夠取代很多專用庫(kù)的工具。在這方面,Windows Workflow Foundation 對(duì)于目前工作流產(chǎn)品的供應(yīng)商也具有重要意義,因?yàn)椴捎?Windows Workflow Foundation 則意味著他們不必再維護(hù)其低級(jí)別的代碼,并且可以集中力量去完成更高級(jí)別的任務(wù)。

Windows Workflow Foundation 是一種面向多種特定應(yīng)用程序和需要的工作流技術(shù)。Windows Workflow Foundation 因而成為一種廣泛的框架,它是為提高每個(gè)級(jí)別的可擴(kuò)展性而設(shè)計(jì)的。這種形式的可擴(kuò)展性的最佳示例是自定義活動(dòng)和可插接的運(yùn)行庫(kù)服務(wù)。自定義活動(dòng)使您可擴(kuò)展可用來(lái)創(chuàng)作工作流的構(gòu)造塊集??筛某志眯源鎯?chǔ)和跟蹤等運(yùn)行庫(kù)服務(wù)以適應(yīng)應(yīng)用程序的環(huán)境,并可使應(yīng)用程序?qū)?shù)據(jù)持久存儲(chǔ)到 Microsoft SQL Server 或其他供應(yīng)商的數(shù)據(jù)庫(kù)中。

Windows Workflow Foundation 的 Visual Studio 2005 擴(kuò)展將允許對(duì)工作流進(jìn)行可視化建模和直接代碼訪問(wèn)。

還可以在其他設(shè)計(jì)環(huán)境中承載可視化設(shè)計(jì)器,從而使設(shè)計(jì)器提供商可以將可視化建模功能嵌入到其自己的環(huán)境中,并且提供應(yīng)用程序用戶所熟悉的用戶體驗(yàn)。

本文僅僅討論了所有 Windows Workflow Foundation 技術(shù)和功能中的一些粗淺知識(shí),提供了有關(guān)其工作方式、內(nèi)部原理的概述和一些有代表性的示例代碼。

關(guān)于作者

Dino Esposito 是一位居住于意大利羅馬的培訓(xùn)師和顧問(wèn)。作為 Wintellect 團(tuán)隊(duì)的成員,Dino 專門研究 ASP.NET 和 ADO.NET,并且花費(fèi)大部分時(shí)間在歐洲和美國(guó)進(jìn)行教學(xué)和咨詢活動(dòng)。值得一提的是,Dino 為 Wintellect 管理 ADO.NET 課件,同時(shí)為 MSDN Magazine 撰寫 Cutting Edge 專欄。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多