BookMark

我们在平时的工作流使用中,并不是直接这样一气呵成将整个工作流直接走完的,通常一个流程到了某一个节点,该流程节点的操作人,可能并不会马上去处理该流程,而只有当处理人处理了该流程,流程才会继续往下走。对于不同流程节点的处理人,他所能处理的是不同的流程节点。

怎么让流程停下来,等待其他用户对流程进行参与处理。并且必须能够保证流程能够在原有的处理现场情况进行保存,而且能够对流程进行继续启动和处理?那就是书签。

就好像我们看书,我们需要书签来标识,我现在已经看到哪个地方了,工作流也是一样的,我需要通过书签,来确定不同角色的人能处理的是哪一个流程。

要定义具备Bookmark的Activit,可从 NativeActivity继承,override [Execute 方法],使用[NativeActivityContext.CreateBookmark方法]添加Bookmark,需要override [ CanInduceIdle 属性],使其返回值为[True]。

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、运行结果如下:

工作流持久化

持久化:工作流持久性是指独立于进程或计算机信息持续捕获工作流实例的状态。持久存储化,例如用磁盘进行存储,光盘存储等持久化的存储数据就是持久化。

为何持久化?财务审批中,提交了审批邀请后,财务总监过了一周才进行审批。那么数据必须进行持久化的保存,等待流程的继续相关处理。
工作流在长时间运行时难免会遇到一些问题,许多业务逻辑需要花费数日、数周乃至数月。在这段时间中,我们不能让工作流实例一直驻留在内存中。

工作流什么时候进行持久化?

  • 当 TransactionScope 活动完成时或 TransactedReceiveScope 活动完成时。
  • 当工作流实例变为空闲状态,且对工作流主机设置了 WorkflowIdleBehavior 时。 例如,当使用消息传递活动或 Delay 活动时会发生此情况。
  • 当 WorkflowApplication 变为空闲状态且将应用程序的 PersistableIdle 属性设置为 PersistableIdleAction.Persist 时。
  • 当指示主机应用程序持久化或卸载工作流实例时。
  • 当终止工作流实例或工作流实例结束时。
  • 当执行 Persist 活动时。
  • 当使用 Windows Workflow Foundation 的早期版本开发的工作流实例在可互操作执行过程中遇到持久点时。

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));
}
}
}

6、我们看数据表中已经多了一条工作流实例数据

7、然后关闭应用程序,再重新启动

从数据库中找到这个ID,然后填写上。

我们看到整个工作流执行完成了,在来看数据表中的工作流实例数据已经删除了。

源码下载:WorkflowConsoleApp3.zip

Workflow笔记3——BookMark和持久化的更多相关文章

  1. Workflow笔记2——状态机工作流

    状态机工作流 在上一节Workflow笔记1——工作流介绍中,介绍的是流程图工作流,后来微软又推出了状态机工作流,它比流程图功能更加强大. 状态机工作流:就是将工作流系统中的所有的工作节点都可以看做成 ...

  2. Workflow笔记2——状态机工作流(转)

    出处:http://www.cnblogs.com/jiekzou/p/6192813.html 在上一节Workflow笔记1——工作流介绍中,介绍的是流程图工作流,后来微软又推出了状态机工作流,它 ...

  3. hibernate学习笔记(2)持久化类测试

    持久化类的创建: 创建一个共有的不带参数的构造方法: public void Students(){ } 创建一个带参数的构造方法: (快捷键创建) 生成get,set方法: *可以不用此方法创建持久 ...

  4. 11/6笔记 补充(Redis持久化,RDB&&AOF)

    11/6补充笔记 修改redis-6379.conf里面的save10秒2个数据发生改变 (save 10 2) 修改一次数据不发生改变,修改2次数据才发生改变 继续修改数据,发现还是一样的规律 增删 ...

  5. Redis6.x学习笔记(二)持久化之RDB

    前言 最近学习Redis6.x,特做笔记以备忘,与大家共学.课程是从私塾在线下载的,他们把架构师课程都放出来了,大家可以去下载学习,不要钱的,地址是http://t.hk.uy/eK7,课程很不错,值 ...

  6. Workflow笔记1——工作流介绍

    什么是工作流? 工作流(Workflow),是对工作流程及其各操作步骤之间业务规则的抽象.概括.描述.BPM:是Business Process Management的英文字母缩写.即业务流程管理,是 ...

  7. docker学习笔记(四)-持久化数据,安装docker-compose

    Docker 持久化数据 实战 compose 安装docker-compose

  8. K8S学习笔记之Kubernetes数据持久化方案

    在开始介绍k8s持久化存储前,我们有必要了解一下k8s的emptydir和hostpath.configmap以及secret的机制和用途. 0x00 Emptydir EmptyDir是一个空目录, ...

  9. [学习笔记]FHQ-Treap及其可持久化

    感觉范浩强真的巨 博主只刷了模板所以就讲基础 fhq-treap 又形象的称为非旋转treap 顾名思义 保留了treap的随机数堆的特点,并以此作为复杂度正确的条件 并且所有的实现不用旋转! 思路自 ...

随机推荐

  1. 【Linux大系】Linux的概念与体系

    感谢原作者:Vamei 出处:http://www.cnblogs.com/vamei 我在这一系列文章中阐述Linux的基 本概念.Linux操作系统继承自UNIX.一个操作系统是一套控制和使用计算 ...

  2. Lind.DDD.LindMQ~关于持久化到Redis的消息格式

    回到目录 关于持久化到Redis的消息格式,主要是说在Broker上把消息持久化的过程中,需要存储哪些类型的消息,因为我们的消息是分topic的,而每个topic又有若干个queue组成,而我们的to ...

  3. centos 6 安装配置openvpn

    下载地址:http://swupdate.openvpn.org/community/releases/http://www.oberhumer.com/opensource/lzo/download ...

  4. linux压力测试工具stress

    最近给PASS平台添加autoscaling的功能,根据服务器的负载情况autoscaling,为了测试这项功能用到了stress这个压力测试工具,这个工具相当好用了.具体安装方式就不说了.记录下这个 ...

  5. 分享MSSQL、MySql、Oracle的大数据批量导入方法及编程手法细节

    1:MSSQL SQL语法篇: BULK INSERT [ database_name . [ schema_name ] . | schema_name . ] [ table_name | vie ...

  6. WPF - 属性系统 (2 of 4)

    属性更改回调 前一章的示例中,对各个参数的设置都非常容易理解.如果我们仅仅需要创建一个独立的依赖项属性,那么上面所提到的创建依赖项属性的基础知识足以满足需求.但是事情往往并非如此完美.在一个系统中,很 ...

  7. 《深入理解Java虚拟机》调优案例分析与实战

    上节学习回顾 在上一节当中,主要学习了Sun JDK的一些命令行和可视化性能监控工具的具体使用,但性能分析的重点还是在解决问题的思路上面,没有好的思路,再好的工具也无补于事. 本节学习重点 在书本上本 ...

  8. Go build constraints

    Go语言有一个不(奇)错(葩)的设计,就是build constraints(构建约束).可以在源码中通过注释的方式指定编译选项,比如只允许在linux下,或者在386的平台上编译啊之类的:还可以通过 ...

  9. java太low,又舍不得jvm平台的丰富资源?试试kotlin吧(一)

    尝试kotlin的起因 因为各种原因(版权,人员招聘),公司的技术体系从c#转到了java,我花了大概两周的时间来上手java,发现java的语法还是非常简单的,基本看着代码就知道什么意思.学习jav ...

  10. CSharpGL(38)带初始数据创建Vertex Buffer Object的情形汇总

    CSharpGL(38)带初始数据创建Vertex Buffer Object的情形汇总 开始 总的来说,OpenGL应用开发者会遇到为如下三种数据创建Vertex Buffer Object的情形: ...