Workflow筆記3——BookMark和持久化

来源:http://www.cnblogs.com/jiekzou/archive/2016/12/18/6194003.html
-Advertisement-
Play Games

BookMark 我們在平時的工作流使用中,並不是直接這樣一氣呵成將整個工作流直接走完的,通常一個流程到了某一個節點,該流程節點的操作人,可能並不會馬上去處理該流程,而只有當處理人處理了該流程,流程才會繼續往下走。對於不同流程節點的處理人,他所能處理的是不同的流程節點。 就好像我們看書,我們需要書簽 ...


BookMark

我們在平時的工作流使用中,並不是直接這樣一氣呵成將整個工作流直接走完的,通常一個流程到了某一個節點,該流程節點的操作人,可能並不會馬上去處理該流程,而只有當處理人處理了該流程,流程才會繼續往下走。對於不同流程節點的處理人,他所能處理的是不同的流程節點。

就好像我們看書,我們需要書簽來標識,我現在已經看到哪個地方了,工作流也是一樣的,我需要通過書簽,來確定不同角色的人能處理的是哪一個流程。

1、在項目WindowsWorkFlowApp中,新建“代碼活動” BookMarkCodeActivity

修改繼承類為NativeActivity,Execute方法的參數類型變為NativeActivityContext類型了。代碼如下:

    public sealed class BookMarkCodeActivity : NativeActivity
    {
        // 定義一個字元串類型的活動輸入參數
        public InArgument<string> BookMarkName { get; set; }
        //定義一個輸出參數,用來做流程判斷,相當於模擬用戶處理流程節點的操作
        public OutArgument<int> Num { get; set; }

        // 創建一個BookMark,讓流程停下來
        protected override void Execute(NativeActivityContext context)
        {
            // 1.獲取BookMark名稱
            string strBookMarkName = context.GetValue(BookMarkName);
            // 2.創建BookMark
            context.CreateBookmark(strBookMarkName,new BookmarkCallback(PreExecuteWorkFlow));
        }
        /// <summary>
        /// 註意,一定要記得註意重寫此屬性,並返回true,否則後面運行會報錯
        /// </summary>
        protected override bool CanInduceIdle
        {
            get
            {
                return true;// base.CanInduceIdle;
            }
        }
        /// <summary>
        /// 繼續執行下一個狀態前,必須先執行該方法。
        /// </summary>
        /// <param name="context"></param>
        /// <param name="bookmark">書簽</param>
        /// <param name="value">傳遞過來的值</param>
        public void PreExecuteWorkFlow(NativeActivityContext context, Bookmark bookmark, object value)
        {
            context.SetValue(Num, Convert.ToInt32(value));
        }
}

2、生成項目WindowsWorkFlowApp

3、雙擊State1打開,將代碼活動添加到State1中,並創建變數Vnum。

4、創建輸入參數InputBookMarkName

5、改造Form1窗體

修改啟動工作流的代碼:

將以WorkflowApplication app;提取到類下麵。

            app = new WorkflowApplication(new Activity1(), new Dictionary<string, object>() { 
            {"InputName","神刀張三"},{"InputBookMarkName",txtBookMarkName.Text}
            });
            app.Idle = delegate(WorkflowApplicationIdleEventArgs er)
            {
                Console.WriteLine("工作流 {0} 空閑.", er.InstanceId);
                syncEvent.Set(); //這裡要喚醒,不讓的話,當創建了一個書簽之後,界面就卡死了。
            };

為“繼續執行”按鈕添加代碼

        //喚醒BookMark執行流程
        private void btnContinue_Click(object sender, EventArgs e)
        {
            //這裡會調用PreExecuteWorkFlow方法,並將txtNum的值傳過去
            app.ResumeBookmark(txtBookMarkName.Text, int.Parse(txtNum.Text));
        }

6、雙擊T1進行修改,添加條件判斷

假設VNum變數的值等於5,則繼續往下執行State2。

7、添加T3,當VNum變數的值不等於5,再回到State1。

雙擊T3,添加條件

8、運行結果如下:

工作流持久化

1、通過創建一個資料庫來持久保存工作流實例。新建資料庫WorkFlowDB:

CREATE DATABASE [WorkFlowDB]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'WorkFlowDB', FILENAME = N'G:\DataBase\WorkFlowDB.mdf' , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
 LOG ON 
( NAME = N'WorkFlowDB_log', FILENAME = N'G:\DataBase\WorkFlowDB_log.ldf' , SIZE = 2048KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO

2、然後新建表來存儲工作流的實例數據,如何新建表?

到%WINDIR%\Microsoft.NET\Framework\v4.xxx\SQL\EN 文件夾下麵去尋找腳本,按Win+R,運行%WINDIR%\Microsoft.NET\Framework

找到這兩個SQL腳本之後,在資料庫WorkFlowDB中首先運行 SqlWorkflowInstanceStoreSchema.sql 文件,然後運行 SqlWorkflowInstanceStoreLogic.sql 文件。執行完成之後,就會在資料庫WorkFlowDB中新建如下表。

InstancesTable表就是用來存儲工作流實例的表。

3、在項目WindowsWorkFlowApp中,添加如下兩個程式集的引用

4、修改工作流啟動代碼

引入命名空間

using System.Activities.DurableInstancing;  

修改btnStartWorkFlow_Click代碼:

            SqlWorkflowInstanceStore store =
    new SqlWorkflowInstanceStore(@"Server=.\MSSQLSERVER2012;database=WorkFlowDB;uid=sa;pwd=yujie1127);
            app.InstanceStore = store;

只需要這兩行代碼,就可以執行持久化工作。那麼當下次重新打開工作流的時候,我需要從資料庫中找到是那一條工作流實例數據,為了演示簡單,我這裡就將工作流實例的主鍵直接放到From窗體界面展示,而通常在工作中,我們是會用數據表來專門存儲這些數據信息的。

5、改造Form1代碼,修改btnContinue_Click

using System;
using System.Activities;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;

using System.Activities.DurableInstancing;  

namespace WindowsWorkFlowApp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        static readonly string ConnStr=@"Server=.\MSSQLSERVER2012;database=WorkFlowDB;uid=sa;pwd=yujie1127";
        //WorkflowApplication app;
        AutoResetEvent syncEvent = new AutoResetEvent(false);
        private void btnStartWorkFlow_Click(object sender, EventArgs e)
        {
            WorkflowApplication app = new WorkflowApplication(new Activity1(), new Dictionary<string, object>() { 
            {"InputName","神刀張三"},{"InputBookMarkName",txtBookMarkName.Text}
            });

            SqlWorkflowInstanceStore store =
    new SqlWorkflowInstanceStore(ConnStr);
            app.InstanceStore = store;
            txtID.Text = app.Id.ToString();

            WorkFlowEvent(app, syncEvent);

            app.Run();

            syncEvent.WaitOne();
        }

        private static void WorkFlowEvent(WorkflowApplication app, AutoResetEvent syncEvent)
        {
            #region 工作流生命周期事件
            app.Unloaded = delegate(WorkflowApplicationEventArgs er)
            {
                Console.WriteLine("工作流 {0} 卸載.", er.InstanceId);
            };
            app.Completed = delegate(WorkflowApplicationCompletedEventArgs er)
            {
                Console.WriteLine("工作流 {0} 完成.", er.InstanceId);
                syncEvent.Set();
            };
            app.Aborted = delegate(WorkflowApplicationAbortedEventArgs er)
            {
                Console.WriteLine("工作流 {0} 終止.", er.InstanceId);
            };
            app.Idle = delegate(WorkflowApplicationIdleEventArgs er)
            {
                Console.WriteLine("工作流 {0} 空閑.", er.InstanceId);
                syncEvent.Set(); //這裡要喚醒,不讓的話,當創建了一個書簽之後,界面就卡死了。
            };
            app.PersistableIdle = delegate(WorkflowApplicationIdleEventArgs er)
            {
                Console.WriteLine("持久化");
                return PersistableIdleAction.Unload;
            };
            app.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs er)
            {
                Console.WriteLine("OnUnhandledException in Workflow {0}\n{1}",
       er.InstanceId, er.UnhandledException.Message);
                return UnhandledExceptionAction.Terminate;
            };
            #endregion
        }

        //喚醒BookMark執行流程
        private void btnContinue_Click(object sender, EventArgs e)
        {
            #region old code
            //這裡會調用PreExecuteWorkFlow方法,並將txtNum的值傳過去
            //app.ResumeBookmark(txtBookMarkName.Text, int.Parse(txtNum.Text)); 
            #endregion

            WorkflowApplication app = new WorkflowApplication(new Activity1());

            SqlWorkflowInstanceStore store =
    new SqlWorkflowInstanceStore(ConnStr);
            app.InstanceStore = store;

            WorkFlowEvent(app, syncEvent);

            app.Load(Guid.Parse(txtID.Text)); //載入工作流實例
            //繼續執行此工作流實例
            app.ResumeBookmark(txtBookMarkName.Text, int.Parse(txtNum.Text)); 
        }
    }
}
View Code

6、我們看數據表中已經多了一條工作流實例數據

7、然後關閉應用程式,再重新啟動

從資料庫中找到這個ID,然後填寫上。

我們看到整個工作流執行完成了,在來看數據表中的工作流實例數據已經刪除了。

源碼下載:WorkflowConsoleApp3.zip


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 裝箱和拆箱 目錄 性能 裝箱 拆箱 介紹 裝箱是將值類型轉換為 object 類型或由此值類型實現的任何介面類型的一個過程。 當 CLR 對值類型進行裝箱時,會將該值包裝到 System.Object 內部,再將後者存儲在托管堆上。 拆箱將從對象中提取值類型。 裝箱是隱式的;拆箱是顯式的。 裝箱和拆 ...
  • 異常介紹 C# 語言的異常處理功能可幫助您處理程式運行時出現的任何意外或異常情況。 異常處理使用 try、catch 和 finally 關鍵字嘗試某些操作,以處理失敗情況,儘管這些操作有可能失敗,但如果您確定需要這樣做,且希望在事後清理資源,就可以嘗試這樣做。 公共語言運行時 (CLR)、.NET ...
  • 學會處理異常 C# 程式員可使用 try 塊對可能受異常影響的代碼進行分區。 關聯的 catch 塊用於處理任何結果異常。 一個包含代碼的 finally 塊,無論 try 塊中是否引發異常(例如,釋放在 try 塊中分配的資源),這些代碼都會運行。 一個 try 塊需要一個或多個關聯的 catch ...
  • 學會使用異常 在 C# 中,程式中的運行時錯誤通過使用一種稱為“異常”的機制在程式中傳播。 異常由錯誤的代碼引發,並由能夠更正錯誤的代碼進行捕捉。 異常可由 .NET 的公共語言運行時 (CLR) 或由程式中的代碼引發。 一旦引發了一個異常,這個異常就會在調用堆棧中向上傳播,直到找到針對它的 cat ...
  • 再次調整項目架構是因為和群友dezhou的一次聊天,我原來的想法是項目儘量做簡單點別搞太複雜了,僅使用了DbContext的註入,其他的也沒有寫介面耦合度很高。和dezhou聊過之後我仔細考慮了一下,還是解耦吧,本來按照軟體設計模式就應該是高內聚低耦合的,低耦合使項目的模塊獨立於其他模塊,增加了可維... ...
  • 因為MongoDb 跨平臺,可以免費使用,讀寫效率高,集群搭建簡單,可以水平擴展等各種因素。 我決定研究一下Mongodb,在查看了相關文檔後發現它對C#的支持不錯,而且還有現成的C#的驅動, 新版的驅動還支持Linq,因為複雜的查詢可以交給Linq去實現。正因為官方的驅動很強大。 剛開始接觸時發現 ...
  • DataTable數據批量寫入資料庫三種方法比較 標簽: it 分類: C#1) insert迴圈插入;2) sqldataadapter.update(dataset,tablename);3) sqlbulkcopy.WriteToServer(datatable);1、生成測試的datatab ...
  • C#使用Jquery zTree實現樹狀結構顯示_非同步數據載入 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...