在沒有持久化之前,流程實例是存在於內存中的,所以我們最多隻能有一個宿主來使用這個流程實例,一旦流程包含多個節點,需要多次使用這個流程實例,那麼流程示例的持久化就是不可或缺的一個過程。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數據庫。
工作流探索剛剛起步