一 概述
在沒有持久化之前,流程執行個體是存在于記憶體中的,是以我們最多隻能有一個宿主來使用這個流程執行個體,一旦流程包含多個節點,需要多次使用這個流程執行個體,那麼流程示例的持久化就是不可或缺的一個過程。Workflow4将工作流持久化封裝成一個插件來提供持久化服務,并且通過調用SqlWorkflowPersistenceService類來實作SQL Server資料中流程執行個體的持久化。
二 工作原理
工作流提供了持久化服務,我們隻需要通過開啟持久化服務即可實作流程執行個體的持久化。在初始化工作流宿主時同時初始化流程執行個體,然後我們就可以在工作流生命周期中的特定時間來進行流程執行個體的持久化。這裡的指定時間有以下幾種情況:
1 工作流空閑時;
2 工作流完成或終止時;
3 活動TransactionScopeActivity/CompensatableTransactionScopeActivity/CompensatableSequenceActiviy 完成時;
4 自定義活動完成時;
5 調用WorkflowInstance的一種方法,且這種方法又會導緻持久化操作時。
對于開發者來說,不需要額外去控制持久化服務,流程執行個體的持久化是由工作流引擎自動控制的。
三 資料模型
1 添加System.Activities.DurableInstancing 和 System.Runtime.DurableInstancing的引用。
2 建立資料庫countersignatureDB;運作C:\Windows\Microsoft.NET\Framework\v4.0.30319\SQL\en下的SqlWorkflowInstanceStoreSchema和SqlWorkflowInstanceStoreLogic腳本,截圖如下:

資料庫表截圖如下:
3 表說明
[System.Activities.DurableInstancing].[InstancesTable] | 執行個體表 |
[System.Activities.DurableInstancing].[RunnableInstancesTable] | 運作執行個體表 |
[System.Activities.DurableInstancing].[KeysTable] | 關鍵字表 |
[System.Activities.DurableInstancing].[LockOwnersTable] | 鎖定表 |
[System.Activities.DurableInstancing].[InstanceMetadataChangesTable] | 執行個體中繼資料變化表 |
[System.Activities.DurableInstancing].[ServiceDeploymentsTable] | 服務部署表 |
[System.Activities.DurableInstancing].[InstancePromotedPropertiesTable] | 執行個體屬性表 |
[System.Activities.DurableInstancing].[SqlWorkflowInstanceStoreVersionTable] | 執行個體版本表 |
[System.Activities.DurableInstancing].[Instances] | 執行個體View |
四 持久化方式
1 比較
我們在前面講了使用開啟持久化服務的方式進行持久化,我們也完全可以使用自定義持久化服務來實作,下面我們對比一下這兩種方式。
優點 | 缺點 | |
WF4持久化 | 1、能夠比較友善利用現有的建表腳本建立持久化需要的資料庫表 2、不用關心流程執行個體持久化發生的時間,運作時引擎會自動處理 3、不用關心如何實作持久化這些技術細節 4、有現有的服務接口可以調用,可擴充 5、完成對流程執行個體整個生命周期的管理 6、同WF 4現有的API易于內建和工作 | 1、僅僅使用現有的表是不夠的,還需要自定義進行擴充資料庫表,如一些設定和參數資訊 2、無法控制流程持久化的時間,需要使用持久化的資料時,資料可能并沒有被持久化 3、受持久化現有服務和接口的制約 4、需要對現有的一些資料庫表進行擴充,這些擴充中的資料和已建表的一些資料要做到同步,增加了事件、事務處理的複雜度 5、開發進度和品質依賴與對SqlWorkflowPersistenceService的掌握程度 6、流程處理的性能需要驗證 7、WF4所帶資料庫是一個黑盒,沒有相關的文檔說明和資料庫設計文檔 |
自定義持久化 | 1、能根據使用者需求完全自定義資料結構和模型 2、能夠控制持久化的時機,對流程資料具有完全的權限 3、降低了流程資料持久化的技術難度 4、統一設計資料模型,減少流程中的事務處理和資料關聯關系 5、針對使用者需求來進行設計 | 1、需要自行設計資料庫模型 2、不能使用WF4 提供現有持久化接口和流程管理與監控的一些功能,這些功能需要自定義開發 3、開發工作量相對較大,但是技術難度會有所降低 |
2 結論
如果我們隻是做一些簡單的流程,軟體比較小,則可選用持久化服務;
如果我們的業務流程比較複雜,功能要求比較多,權限要求比較高,則可選用自定義服務來實作。
五 實作
1 代碼
//自定義節點
<span style="font-size:18px;"> class PersistActivity : NativeActivity
{
//節點預設執行的方法
protected override void Execute(NativeActivityContext context)
{
//建立書簽,此書簽可以讓工作流進入Idle狀态以進行工作流持久化
context.CreateBookmark("bookmarkTest",new BookmarkCallback(this.Continue));
}
/// <summary>
///重新啟動流程時的回調函數
/// </summary>
/// <param name="context">流程上下文</param>
/// <param name="bookmark">流程可以被恢複的點</param>
/// <param name="obj">流程恢複是需要關聯的資料</param>
void Continue(NativeActivityContext context, Bookmark bookmark, object obj)
{
}
//設定此節點是否可以被持久化,預設傳回值為true
protected override bool CanInduceIdle
{
get
{
return true;
}
}
}
</span>
<pre name="code" class="csharp"><span style="font-size:18px;"> class Program
{
public static AutoResetEvent async = new AutoResetEvent(false);
static void Main(string[] args)
{
//資料庫連接配接字元串
string sqlConnectionString = "server=.;database=countersignatureDB;uid=sa;password=123456";
SqlWorkflowInstanceStore instanceStore = new SqlWorkflowInstanceStore(sqlConnectionString);
InstanceView view = instanceStore.Execute(instanceStore.CreateInstanceHandle(), new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(10));
instanceStore.DefaultInstanceOwner = view.InstanceOwner;
//建立宿主,并設定持久化對象
WorkflowApplication application = new WorkflowApplication(new PersistActivity());
application.InstanceStore = instanceStore;
//給各事件注冊方法
application.Idle += workflowIdle;
application.Unloaded += workflowUnload;
application.PersistableIdle += workflowPersistabled;
//資料持久化
application.Persist();
application.Run();
async.WaitOne();
Console.ReadKey();
}
//定義工作流進入空閑狀态時執行的事件
static void workflowIdle(WorkflowApplicationIdleEventArgs e)
{
Console.WriteLine("WorkflowIdle" + e.Bookmarks.FirstOrDefault().BookmarkName);
}
//定義工作流進入解除安裝狀态時執行的事件
static void workflowUnload(WorkflowApplicationEventArgs e)
{
Console.WriteLine("WorkflowUnloaded" + System.DateTime.Now.ToString());
//給主線程傳回資訊,傳回到主線程繼續執行
async.Set();
}
//定義工作流進入空閑狀态并且可被持久化時執行的事件
static PersistableIdleAction workflowPersistabled(WorkflowApplicationIdleEventArgs e)
{
Console.WriteLine("WorkflowPersist" + System.DateTime.Now.ToString());
/*PersistableIdleAction為枚舉對象,共三個枚舉,None、Unload、Persist
*1 None為宿主不進行任何操作
*2 Persist位宿主保持工作流
*3 Unload為宿主解除安裝目前工作流,其他宿主就可以重新開機此工作流了
*/
return PersistableIdleAction.Unload;
}
//定義工作流發生異常時執行的事件
static UnhandledExceptionAction workflowUnhandledException(WorkflowApplicationUnhandledExceptionEventArgs e, UnhandledExceptionAction action)
{
Console.WriteLine("WorkflowException" + e.UnhandledException.Message);
return UnhandledExceptionAction.Terminate;
}
}</span>
2 說明
我們首先在自定義活動中,設定此節點是可以被執行個體化的;然後添加重新開機流程的回調函數,此方法可以在流程重新開機時首先執行,進而處理我們自定義的一些活動;最後建立書簽,建立書簽可以使工作流運作到此節點時将狀态修改為Idle,進而進行持久化。
宿主程式中,我們首先設定資料庫連接配接字元串,然後建立持久化對象SqlWorkflowInstanceStore,并且将連接配接字元串傳入持久化對象;然後我們建立宿主對象,并且将宿主的InstanceStore屬性設定為持久化對象來制定使用的持久化存儲;接着,我們給流程的各個事件注冊我們預先定義好的方法;最後,我們啟動流程,并且使用AutoResetEvent對象來實作多線程。
3 程式輸出結果
4 資料庫資料更新
六 注意事項
1 自定義節點中,必須要設定是否可以被持久化屬性,否則不能實作持久化;
2 自定義節點中,必須要設定書簽,否則工作不會進入Idle空閑狀态,進而進行持久化操作;
3 宿主程式中,一定要手動進行流程持久化存儲,也就是說需要顯示調用WorkflowApplication.Persist()方法進行資料持久化;
4 必須阻塞主線程,否則主線程執行結束時,建立、運作和持久化流程的從線程不會執行結束,進而不能實作流程持久化;
5 如果想要實作多次使用此流程,則持久化工作流時需要選擇PersistableIdleAction.Unload,即保持并解除安裝工作流方式,此方式可以使目前宿主放棄鎖定流程執行個體,進而可以實作另外的宿主重新開機此流程。
七 總結
大多數的流程都會用到持久化功能,這個功能目前使用比較成熟,常用的持久化方式包括資料庫方式和XML方式,資料庫方式小編隻實作了SQL Server資料庫。
工作流探索剛剛起步