WWF提供的持续化功能会自动记录工作流实例以及它包含的所有活动的执行状态,这些状态并不是指工作流上流转的表单所呈现的业务逻辑状态。WWF持续化功能就是将未执行完成的工作流实例以及该实例中各种活动的状态,以文件或数据库方式进行存储,待需要的时候再重新将其加载回工作流运行时容器Runtime中。运行完毕才删除。

  在具体操作中通过"SqlWorkflowPersistenceService"类来实现持续化的功能,基于数据库,其他数据库需重新实现接口。

一、创建SqlPersistenceService数据库

  要在SQLServer实现工作流的保存、恢复功能,需要创建一些相关表与存储过程。默认情况下在C:\Windows\Microsoft.NET\Framework\v3.5\SQL\EN 路径下有SqlPersistenceProviderSchema.sql和SqlPersistenceProviderLogic.sql两个文件,打开SQLServer创建一个名叫SqlPersistenceService的数据库,按顺序执行以上两个sql脚本。此时,SqlPersistenceService数据库就创建了几个表与存储过程。

  如果实在不行,就把SqlPersistenceService数据库附加进来。http://files.cnblogs.com/kissdodog/WWF%E6%8C%81%E7%BB%AD%E5%8C%96%E6%95%B0%E6%8D%AE%E5%BA%93.rar

  接口如下:

   [ExternalDataExchange]  //using System.Workflow.Activities;
public interface IEvent
{
event EventHandler<ExternalDataEventArgs> PMApproved;
event EventHandler<ExternalDataEventArgs> VPApproved;
event EventHandler<ExternalDataEventArgs> StaffSubmit;
}

  新建一个工作流如下:

  

  里面是3个HandleExternalEvent活动,分别于刚刚定义的接口事件相绑定。

  

  在bin目录里面添加一个XML文件,其代码如下:

<WorkflowInstances />

  新建一个Winform程序,界面如下:

  

  代码如下:

    public partial class Form1 : Form, ClassLibrary1.IEvent
{
//创建一个WinForm引用程序,然后继承并实现接口中定义的事件
public event EventHandler<ExternalDataEventArgs> PMApproved;
public event EventHandler<ExternalDataEventArgs> VPApproved;
public event EventHandler<ExternalDataEventArgs> StaffSubmit; private WorkflowRuntime runtime;
//SQLServer中的"SqlPersistenceService"数据库是用来存储工作流实例及其活动的运行状态。
//业务逻辑状态也能够以XML文件形式进行存储,当程序刚运行无流程在运行时,添加一个空xml文件
//名为:workflowInstances.xml直接放在bin目录
const string instanceFilename = "workflowInstances.xml"; WorkflowInstance instance; public Form1()
{
InitializeComponent(); this.runtime = new WorkflowRuntime(); runtime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(runtime_WorkflowCompleted);
runtime.WorkflowIdled += OnWorkflowIdled; //应用程序启动时以"SqlWorkflowPersistenceService"为对象来实例化"WorkflowPersistenceService"类,
//并通过"SqlWorkflowPersistenceService"来连接SQLServer数据库,同时将工作流的持续化服务加载到工作流运行时容器Runtime中。
WorkflowPersistenceService persistenceService =
new SqlWorkflowPersistenceService(
"server=CZZ;database=SqlPersistenceService;uid=sa;pwd=123");
runtime.AddService(persistenceService); ExternalDataExchangeService dataService = new ExternalDataExchangeService();
runtime.AddService(dataService); dataService.AddService(this); LoadWorkflowData(); runtime.StartRuntime(); }
//在工作流空闲状态时并将其从内存中卸载出去
//重载工作流的"WorkflowIdled"事件,当工作流处于等待状态下时将通过该事件来调用工作流实例的"TryUnload()"方法,
//使它激发工作流的"WorkflowPersisted"事件,这样工作流就可以通过"WorkflowPersistenceService"服务将信息自动保存到SQL Server数据库,以实现持续化功能。
static void OnWorkflowIdled(object sender, WorkflowEventArgs e)
{
e.WorkflowInstance.TryUnload();
} //当工作流完成后,将界面列表中的相应数据删除
//当工作流运行结束时还需要对界面列表中的相关信息进行删除,用户可以通过重载工作流的"WorkflowCompleted"事件来实现。
//要注意分清楚,事件是工作流的事件,而删除界面是WinForm程序的事。工作流与应用程序不在同一个线程,因此不能直接调用。这种情况可以通过委托来实现。
void runtime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
{
RemoveListViewItem remove = new RemoveListViewItem(RemoveListViewItemAsync);
Invoke(remove, e.WorkflowInstance.InstanceId);
}
private delegate void RemoveListViewItem(Guid instanceId);
private void RemoveListViewItemAsync(Guid instanceId)
{
foreach (ListViewItem item in ListViewExisting.Items)
{
if (item.SubItems[].Text.Equals(instanceId.ToString()))
ListViewExisting.Items.Remove(item);
}
} //用户提交请假单的按钮事件
private void btnSubmit_Click(object sender, EventArgs e)
{
instance = runtime.CreateWorkflow(typeof(WorkflowConsoleApplication1.Workflow1));
instance.Start(); StaffSubmit(null, new ExternalDataEventArgs(instance.InstanceId)); ListViewExisting.Items.Add(new ListViewItem(new String[] { instance.InstanceId.ToString(), this.txtDay.Text, "提交请假单" })); }
//当窗体关闭时,将列表中请假单的信息保存到XML中
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
SaveWorkflowData();
runtime.Dispose();
}
//项目经理审批的按钮
private void btnPMArrpoved_Click(object sender, EventArgs e)
{
instance = runtime.GetWorkflow(new Guid(ListViewExisting.SelectedItems[].Text)); PMApproved(null, new ExternalDataEventArgs(instance.InstanceId)); foreach (ListViewItem item in ListViewExisting.Items)
{
if (item.SubItems[].Text.Equals(instance.InstanceId.ToString()))
item.SubItems[].Text = "等待VP审批";
}
}
//副总经理审批的按钮
private void btnVPApproved_Click(object sender, EventArgs e)
{
instance = runtime.GetWorkflow(new Guid(ListViewExisting.SelectedItems[].Text));
VPApproved(null, new ExternalDataEventArgs(instance.InstanceId));
foreach (ListViewItem item in ListViewExisting.Items)
{
if (item.SubItems[].Text.Equals(instance.InstanceId.ToString()))
item.SubItems[].Text = "审批通过";
}
}
#region 读写XML的方法
/// <summary>
/// 从XML文件中读取已经钝化的工作流实例的信息
/// </summary>
public void LoadWorkflowData()
{
XmlTextReader reader = new XmlTextReader(instanceFilename);
try
{
while (reader.Read())
{
if (reader.Name.Equals("WorkflowInstance"))
{
ListViewExisting.Items.Add(
new ListViewItem(
new String[] { reader.GetAttribute("InstanceId"),
reader.GetAttribute("Day"),
reader.GetAttribute("State")}));
}
}
reader.Close();
}
catch (FileNotFoundException) { }
}
/// <summary>
/// 保存工作流实例的信息到XML文件中
/// </summary>
public void SaveWorkflowData()
{
XmlTextWriter writer = new XmlTextWriter(instanceFilename, Encoding.Unicode);
writer.WriteStartElement("WorkflowInstances");
foreach (ListViewItem item in ListViewExisting.Items)
{
writer.WriteStartElement("WorkflowInstance");
writer.WriteAttributeString("InstanceId", item.SubItems[].Text);
writer.WriteAttributeString("Day", item.SubItems[].Text);
writer.WriteAttributeString("State", item.SubItems[].Text);
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.Flush();
writer.Close();
}
#endregion
}

  执行效果如下:

  

  由于在关闭窗口的时候,会将当前工作流的执行状态保存到XML文件和数据库中,而下次打开的时候,回去读取上次执行到的状态,所以当工作流执行到某一步关闭窗口再打开,会显示上次保存的状态。

WWF3的持续化<第五篇>的更多相关文章

  1. 【Python五篇慢慢弹(4)】模块异常谈python

    模块异常谈python 作者:白宁超 2016年10月10日12:08:31 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给出的pythondo ...

  2. 前端工程师技能之photoshop巧用系列第五篇——雪碧图

    × 目录 [1]定义 [2]应用场景 [3]合并[4]实现[5]维护 前面的话 前面已经介绍过,描述性图片最终要合并为雪碧图.本文是photoshop巧用系列第五篇——雪碧图 定义 css雪碧图(sp ...

  3. WWF3追踪功能<WWF第六篇>

    WWF工作流提供了Tracking跟踪功能来对工作流实例及其所包含的活动在运行时的状态进行跟踪,以便用户在需要时可以通过这些历史信息进行分析.WWF的Tracking跟踪功能是通过"SqlT ...

  4. ElasticSearch入门 第五篇:使用C#查询文档

    这是ElasticSearch 2.4 版本系列的第五篇: ElasticSearch入门 第一篇:Windows下安装ElasticSearch ElasticSearch入门 第二篇:集群配置 E ...

  5. 持续化集成Jenkins的系统配置

    最近在研究selenium2自动化测试,用到持续化集成jenkins.由于之前仅限于使用,而没有真正动手配置过,所以现在学习从零开始,搭建持续化集成,故而有了这篇博客. 先介绍一下项目持续集成测试,这 ...

  6. mysql第五篇 : MySQL 之 视图、触发器、存储过程、函数、事物与数据库锁

    第五篇 : MySQL 之 视图.触发器.存储过程.函数.事物与数据库锁 一.视图 视图是一个虚拟表(非真实存在的),其本质是‘根据SQL语句获取动态的数据集,并为其命名‘ ,用户使用时只需使用“名称 ...

  7. 【Python五篇慢慢弹】快速上手学python

    快速上手学python 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多 ...

  8. 【Python五篇慢慢弹】数据结构看python

    数据结构看python 作者:白宁超 2016年10月9日14:04:47 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给出的pythondoc ...

  9. 【Python五篇慢慢弹(3)】函数修行知python

    函数修行知python 作者:白宁超 2016年10月9日21:51:52 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给出的pythondoc ...

随机推荐

  1. DBA_Oracle PFile and SPFile文件的管理和使用(案例)

    2014-08-25 Created By BaoXinjian

  2. 深入Java集合学习系列:HashMap的实现原理

    1.    HashMap概述: HashMap是基于哈希表的Map接口的非同步实现.此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序恒久不变 ...

  3. Salted Password Hashing

    Here are some examples of poor wacky hash functions I've seen suggested in forums on the internet. m ...

  4. android 技术相关Blog

    android 技术相关 LVXIANGAN的专栏 http://blog.csdn.net/LVXIANGAN/article/category/1101038 Android NFC 开发实例 h ...

  5. 20145305《Java程序设计》实验三

    (一)敏捷开发与XP 1.了解什么是敏捷开发 敏捷开发(Agile Development)是一种以人为核心.迭代.循序渐进的开发方法."敏捷流程"是一系列价值观和方法论的集合. ...

  6. 90、 Android UI模板设计

    第一步:自定义xml属性 新建一个android项目,在values文件夹中新建一个atts.xml的文件,在这个xml文件中声明我们一会在使用自定义控件时候需要指明的属性.atts.xml < ...

  7. Centos下搭建ftp服务器

    完全不用那么麻烦,直接可以用xshell中自带的传输文件功能,下载客户端xftp安装就行,不用配置,可以在windows系统向Linux系统的任何文件地方上传下载文件,简单方便,大大节约时间, vsf ...

  8. C++学习5

    类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量:创建对象的过程也叫类的实例化.每个对象都是类的一个具体实例(Instance),拥有类的成员变量和成员函数. 与结构体一样,类 ...

  9. [Java] 匿名内部类

    package test.file; import java.io.File; import java.io.FilenameFilter; /** * 匿名的内部类 * @author Frost. ...

  10. Address already in use: JVM_Bind<null>:8080错误的解决办法

    myEclipse在启动tomcat时,有时候会出现8080端口被占用的情况, 提示这个错误:Address already in use: JVM_Bind<null>:8080. 按照 ...