學習完本章後,你將掌握:
1.在你的應用程序中使用workflow
2.理解“WorkflowRuntime”對象的的基本功能
3.知道如何啟動和停止workflow運行時
4.能夠使用各種workflow運行時的相關事件
當你在WF環境中執行任務時,需要一些東西來監管執行的過程,這個東西就是命名為“WorkflowRuntime”的對象。WorkflowRuntime啟動一個獨立的工作流任務。在你的任務執行過程中,WorkflowRuntime也會針對不同的情況響應對應的事件。並且,WorkflowRuntime還能在你的執行環境中增加一個附加的服務來保持跟蹤。
WF架構縱覽見下圖:
WF和你的應用程序並行執行。其實,我們需要你的應用程序作為宿主。宿主應用程序可以是Windows Forms應用程序,控制台應用程序,ASP.NET WEB應用程序,甚至可以是一個Windows Server。WF運行時和你的應用程序同在一個.NET應用程序域執行,每個應用程序域只有一個唯一的WorkflowRuntime實例,試圖在一個應用程序域中建立第二個WorkflowRuntime的實例的話,其結果就是拋出一個“InvalidOperationException”異常。
workflow應用程序-“workflows”-意思指創建的邏輯上的一組活動。這些邏輯上的活動用來完成你需要的工作流任務。當你宿主workflow運行時的時候,其實你就在操作工作流中的活動並讓workflow運行時執行他們。其結果就是生成一個workflow實例,workflow實例是一個當前正執行的workflow任務,它能自己完成邏輯上的一組活動,回憶第一章吧,活動能執行你提供的代碼並且能對輸入的數據做出相應的決定。下一章我們將簡述工作流實例,後面幾章將對活動進行介紹。
在宿主應用程序中添加WF
一、創建一個名稱為WorkflowHost的控制台應用程序項目
二、為項目添加名為System.Workflow.Runtime的引用
三、宿主workflow運行時
1.打開Program.cs文件准備編輯
2.在“using System.Text;”下添加以下代碼:
“using System.Workflow.Runtime”
3.定位到“Main”方法,在裡面添加以下代碼:
WorkflowRuntime workflowRuntime=new WorkflowRuntime();
4.編譯程序確認沒有錯誤。在本章我們都將使用這一應用程序。
四、深入了解WorkflowRuntime對象
我們現在已經在我們的宿主應用程序中建立了一個WorkflowRuntime類型的實例,該是簡單的了解怎樣和這個對象交互的時候了。和大多數有用的對象一樣,WorkflowRuntime也暴露了一些方法和屬性,我們可用他們來控制Workflow運行時的環境。表2-1列出了所有WorkflowRuntime屬性,表2-2則列出了我們經常使用的方法。
表2-1 WorkflowRuntime的屬性
屬性 功能 IsStarted 用來指明workflow運行時是否已經啟動並准備接受workflow實例。當宿主調用“StartRuntime”前IsStarted為False。期間它一直維持True直到宿主調用“StopRuntime”為止。需注意的是當它正在運行中你不能增加核心服務。 Name 獲取或設置和WorkflowRuntime關聯的名字。Workflow運行時正在運行中你不能設置這個屬性(也就是說當IsStarted為True)。企圖這樣做的結果就是拋出一個“InvalidOperationException”異常。
表2-2 WorkflowRuntime的方法
方法 功能 AddService 為workflow運行時添加指定的服務。能添加的服務類型和時間受到種種限制。關於服務的詳細信息將在第五章介紹。 CreateWorkflow 創建一個workflow實例,它包含一些指定(但可選)的參數。假如workflow運行時沒有啟動,該方法就調用StartRuntime方法。 GetWorkflow 通過指明workflow實例的標識符(由一個Guid組成)來檢索workflow實例。假如這個workflow實例是空閒和持久化保存的,它將被重新加載並執行。 StartRuntime 啟動workflow運行時和相關服務,並引發“Started”事件。 StopRuntime 停止workflow運行時和相關服務,並引發“Stoped”事件。
還有更多的關於WorkflowRuntime的方法,但表2-2中列出的方法是最經常用到的方法,也是我們將重點關注的方法。在workflow運行期間,WorkflowRuntime也將在各種時間引發許多事件,但我們將在後面的章節中介紹。
創建一個Workflow運行時工廠
單例和工廠設計模式的組合是強大的,因為工廠能保證只創建出一個曾創建的對象的單一實例,這正好符合我們的要求(在這裡使用單例模式的原因主要是從效率上考慮,其次一個應用程序域也只能只有一個WorkflowRuntime),因為WorkflowRuntime完全有可能在不同的應用當中加載和啟動(例如獨立的應用模塊)。讓我們看看怎樣創建一個WorkflowRuntime工廠。
一、在項目中添加一個類型為類的新項,文件名為WorkflowFactory.cs。
二、在WorkflowFactory.cs源文件中添加如下的引用
using System.Workflow.Runtime;
三、在類中添加下面的代碼: //workflow runtime的單一實例
private static WorkflowRuntime _workflowRuntime = null;
private static object _syncRoot = new object();
四、在上述代碼後添加如下方法:
//工廠方法
public static WorkflowRuntime GetWorkflowRuntime()
{
//多線程環境下防止並發訪問
lock (_syncRoot)
{
if (null == _workflowRuntime)
_workflowRuntime = new WorkflowRuntime();
}
return _workflowRuntime;
}
五、為類加上Public關鍵字,為防止類被直接實例化,還必須為類加上static標記,如下所示:
public static class workflowFactory
啟動workflow運行時
參考表2-2,裡面有一個StartRuntime方法,從我們的工廠對象中調用這個方法很有意義,外部對象要求workflow運行時對象無需處理或擔心運行時環境狀態的初始化。我們需要在我們的應用程序通過這一步來建立我們需要的workflow環境。外部調用對象也需要workflow運行時對象易於使用。
並不是一定要調用StartRuntime。假如我們建立了一個workflow實例,StartRuntime實際上就已被調用。假如我們曾經創建了一個workflow實例,或許並不用擔心需要明確的調用StartRuntime。但是,一旦我們添加服務時,明確地調用它就很有必要,因為可增強代碼的可維護性並確信運行時環境的狀態已建立,這樣任何人就都能使用workflow運行時對象。
因此讓我們在我們的工廠對象中做些輕微的更改並直接調用StartRuntime。
1.打開WorkflowFactory.cs文件並定位到下面的代碼上:
_workflowRuntime = new WorkflowRuntime();
2.在上面的代碼下添加以下的代碼:
_workflowRuntime.Starttime();
停止workflow運行時
是否有辦法啟動一個workflow運行時很有意義,如何停止一個workflow運行時也一樣。看看表2-2吧,裡面有一個StopRuntime方法正好符合我們要求。調用StopRuntime方法會卸載所有正執行的workflow和服務並關閉workflow運行時環境。當然,正確調用StopRuntime位置是在你申請停止邏輯結束之前或者應用程序域關閉前調用。
1.打開WorkflowFactory.cs文件並定位到下面的代碼上
_workflowRuntime = new WorkflowRuntime();
2.在上面代碼的前面增加以下代碼:
_workflowRuntime.Starttime();
3.在WorkflowFactory.cs中增加StopWorkflowRuntime事件處理函數:
static void StopWorkflowRuntime(object sender, EventArgs e)
{
if (_workflowRuntime != null)
{
if (_workflowRuntime.IsStarted)
{
try
{
_workflowRuntime.StopRuntime();
}
catch (ObjectDisposedException)
{
}
}
}
}
以下是WorkflowFactory.cs文件的完整源代碼,在第五章之前我們不會做更多的改變:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Workflow.Runtime;
namespace WorkflowHost
{
public static class WorkflowFactory
{
//workflow runtime的單一實例
private static WorkflowRuntime _workflowRuntime = null;
private static object _syncRoot = new object();
//工廠方法
public static WorkflowRuntime GetWorkflowRuntime()
{
//多線程環境下防止並發訪問
lock (_syncRoot)
{
if (null == _workflowRuntime)
{
AppDomain.CurrentDomain.ProcessExit += new EventHandler(StopWorkflowRuntime);
AppDomain.CurrentDomain.DomainUnload += new EventHandler(StopWorkflowRuntime);
_workflowRuntime = new WorkflowRuntime();
_workflowRuntime.StartRuntime();
}
}
return _workflowRuntime;
}
static void StopWorkflowRuntime(object sender, EventArgs e)
{
if (_workflowRuntime != null)
{
if (_workflowRuntime.IsStarted)
{
try
{
_workflowRuntime.StopRuntime();
}
catch (ObjectDisposedException)
{
}
}
}
}
}
}
現在我們有了一個workflow運行時的創建工廠,然後我們將修改我們的主程序來使用它。
使用workflow運行時創建工廠
1.打開Program.cs文件並定位到如下代碼上:
WorkflowRuntime workflowRuntime=new WorkflowRuntime();
2.把上面的代碼修改成以下代碼:
WorkflowRuntime workflowRuntime=WorkflowFactory.GetWorkflowRuntime();
表2-3 workflow運行時的相關事件描述
事件 功能 Started 當workflow運行時啟動後激發。 Stopped 當workflow運行時停止後激發。 WorkflowCompleted 當一個workflow實例完成後激發。 WorkflowIdled 當一個workflow實例進入空閒狀態時激發。當workflow實例進入了空閒狀態後,你就有機會把他們從內存中卸載掉、存儲到數據庫並可在稍後的時間把它們加載進內存。 WorkflowTerminated 當一個workflow實例被終止後激發。在宿主中調用一個workflow實例的Terminate方法、或通過一個Terminate活動、或當workflow運行時產生一個未經捕獲的異常時都會終止該workflow。
我們還將在第四章和第五章介紹更多的事件。
在我們為上面的事件添加相應的事件處理程序時,你會看到生成的代碼和上一章我們創建的基於工作台的順序工作流應用程序中的代碼完全一樣(或幾乎完全一樣)。為了看看這些事件的作用,我們需要停止應用程序主線程一段時間。因此,我們使用一個基於內核的自動重置事件。一會兒後,我們將寫出一些代碼來使用上述事件中的幾個,你需要不時看看第一章中PCodeFlow項目中的Program.cs文件,對比它們的不同以及該寫入什麼樣的代碼。盡管它們並不完全相同,但你在兩個程序中還是能找到相同的內容。
處理workflow運行時事件
1.啟動Visual Studio,打開項目的Program.cs源文件,定位到下面的代碼上:
WorkflowRuntime workflowRuntiem=WorkflowFactory.GetWorkflowRuntime();
2.假如你用過.NET的委托,下面的代碼你將非常熟悉。我們需要為我們感興趣的事件增加相應的事件處理程序。我們現在就來為workflow空閒時和完成後增加相應的事件處理程序。稍候我們還會增加我們所需要的更多的事件處理程序。記住,下面的代碼在步驟1定位的代碼的下面:
workflowRuntime.WorkflowIdled += new EventHandler<WorkflowEventArgs>(workflowIdled);
3.下面的代碼添加了對workflow完成後的事件處理:
workflowRuntime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(workflowCompleted);
4.現在添加對workflow終止後的事件處理:
workflowRuntime.WorkflowTerminated += new EventHandler<WorkflowTerminatedEventArgs>(workflowTerminated);
5.假如你編譯並運行WorkflowHost(本項目),這個應用程序能通過編譯並運行。但沒有執行workflow,因為我們並未告知workflow運行時去啟動一個workflow實例(我們將在下章添加)。為以後做准備,我們還要添加一些代碼。首先,為了激發workflow中的事件(以便我們觀察它們),我們需要停止主線程足夠長的時間,因此我們還將添加自動重置事件。在步驟3、4的代碼下添加以下代碼。
Console.WriteLine("對待workflow完成。");
waitHandle.WaitOne();
Console.WriteLine("完成.");
6.在Main方法前定義一個名為waitHandle的靜態成員:
private static AutoResetEvent waitHandle = new AutoResetEvent(false);
7.添加名稱空間:
using System.Threading;
8.由Vistual Studio 2008創建的上面三個事件對應的事件處理程序內都包含“throw new NotImplementedException();”。我們需要移除這些代碼並定位到workflowIdled的事件處理程序內,寫入下面的代碼:
Console.WriteLine("workflow實例空閒中");
9.定位到workflowCompleted的事件處理程序內,寫入下面的代碼:
Console.WriteLine("workflow實例已完成");
waitHandle.Set();
10.定位到workflowTerminated的事件處理程序內,寫入下面的代碼:
Console.WriteLine("workflow實例已終止,原因:'{0}'。",e.Exception.Message);
waitHandle.Set();
完整的代碼見列表2-2。
列表2-2 WorkflowHost應用程序的完整代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Workflow.Runtime;
using System.Threading;
namespace WorkflowHost
{
class Program
{
private static AutoResetEvent waitHandle = new AutoResetEvent(false);
static void Main(string[] args)
{
WorkflowRuntime workflowRuntime = WorkflowFactory.GetWorkflowRuntime();
workflowRuntime.WorkflowIdled += new EventHandler<WorkflowEventArgs>(workflowRuntime_WorkflowIdled);
workflowRuntime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(workflowRuntime_WorkflowCompleted);
workflowRuntime.WorkflowTerminated += new EventHandler<WorkflowTerminatedEventArgs>(workflowRuntime_WorkflowTerminated);
Console.WriteLine("等待workflow完成。");
waitHandle.WaitOne();
Console.WriteLine("完成.");
}
static void workflowRuntime_WorkflowIdled(object sender, WorkflowEventArgs e)
{
Console.WriteLine("workflow實例空閒中");
}
static void workflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
{
Console.WriteLine("workflow實例已完成");
waitHandle.Set();
}
static void workflowRuntime_WorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine("workflow實例已終止,原因:'{0}'。",e.Exception.Message);
waitHandle.Set();
}
}
}
下一章我們將深入workflow實例,假如現在你執行這個程序,他會一直掛起。為什麼呢?因為我們從未執行一個workflow實例,因此我們加入的事件的從未被激發,也就未執行對應的事件處理程序。程序將永遠掛起(或者你親自終止它)。在下一章中當我們添加一個workflow實例並執行它時我們還會看到這個程序。
本文配套源碼