WWF3的持续化<第五篇>
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的持续化<第五篇>的更多相关文章
- 【Python五篇慢慢弹(4)】模块异常谈python
模块异常谈python 作者:白宁超 2016年10月10日12:08:31 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给出的pythondo ...
- 前端工程师技能之photoshop巧用系列第五篇——雪碧图
× 目录 [1]定义 [2]应用场景 [3]合并[4]实现[5]维护 前面的话 前面已经介绍过,描述性图片最终要合并为雪碧图.本文是photoshop巧用系列第五篇——雪碧图 定义 css雪碧图(sp ...
- WWF3追踪功能<WWF第六篇>
WWF工作流提供了Tracking跟踪功能来对工作流实例及其所包含的活动在运行时的状态进行跟踪,以便用户在需要时可以通过这些历史信息进行分析.WWF的Tracking跟踪功能是通过"SqlT ...
- ElasticSearch入门 第五篇:使用C#查询文档
这是ElasticSearch 2.4 版本系列的第五篇: ElasticSearch入门 第一篇:Windows下安装ElasticSearch ElasticSearch入门 第二篇:集群配置 E ...
- 持续化集成Jenkins的系统配置
最近在研究selenium2自动化测试,用到持续化集成jenkins.由于之前仅限于使用,而没有真正动手配置过,所以现在学习从零开始,搭建持续化集成,故而有了这篇博客. 先介绍一下项目持续集成测试,这 ...
- mysql第五篇 : MySQL 之 视图、触发器、存储过程、函数、事物与数据库锁
第五篇 : MySQL 之 视图.触发器.存储过程.函数.事物与数据库锁 一.视图 视图是一个虚拟表(非真实存在的),其本质是‘根据SQL语句获取动态的数据集,并为其命名‘ ,用户使用时只需使用“名称 ...
- 【Python五篇慢慢弹】快速上手学python
快速上手学python 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多 ...
- 【Python五篇慢慢弹】数据结构看python
数据结构看python 作者:白宁超 2016年10月9日14:04:47 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给出的pythondoc ...
- 【Python五篇慢慢弹(3)】函数修行知python
函数修行知python 作者:白宁超 2016年10月9日21:51:52 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给出的pythondoc ...
随机推荐
- DBA_Oracle AWR Report性能监控报表(案例)
2014-08-22 Created By BaoXinjian
- POJ2226 Muddy Fields 二分匹配 最小顶点覆盖 好题
在一个n*m的草地上,.代表草地,*代表水,现在要用宽度为1,长度不限的木板盖住水, 木板可以重叠,但是所有的草地都不能被木板覆盖. 问至少需要的木板数. 这类题的建图方法: 把矩阵作为一个二分图,以 ...
- Linux命令(17)du 查看文件和目录磁盘使用情况
Linux du命令也是查看使用空间的,但是与df命令不同的是Linux du命令是对文件和目录磁盘使用的空间的查看,还是和df命令有一些区别的. 1.命令格式: du [选项][文件] 2.命令功能 ...
- Java代码规范、格式化和checkstyle检查配置文档
http://www.blogjava.net/amigoxie/archive/2014/05/31/414287.html 文件下载: http://files.cnblogs.com/files ...
- js swipe 图片滑动控件实现 任意尺寸适用任意屏幕
http://www.swiper.com.cn/http://www.idangero.us/swiper/demos/ 解决问题点: 1.先得到图片真实的宽高, 根据真实宽高 等比例 2.调用的控 ...
- http://www.imooc.com/video/4767 zepto教学视频笔记
一.介绍js移动端框架:zepto.js与jquery mobile 对比:zepto特点 1.与jquery相似度95%,会jquery基本会zepto: 2.API少,轻量级框架 3.移动端无缝接 ...
- phpStudy(lnmp)集成环境安装
phpStudy phpStudy » PHP教程 » phpStudy for Linux (lnmp+lamp一键安装包) phpStudy for Linux (lnmp+lamp一键安装包) ...
- Winform 通过FlowLayoutPanel及自定义的编辑控件,实现快速构建C/S版的编辑表单页面 z
http://www.cnblogs.com/zuowj/p/4504130.html 不论是B/S或是C/S结构类型,无非就是实现可供用户进行查.增.改.删,其中查询用到最多,开发设计的场景 也最为 ...
- 96、facebook Fresco框架库源使用基础
开源项目链接 facebook Fresco仓库:git clone https://github.com/facebook/fresco facebook Fresco主页:“>http:// ...
- C++学习10 static静态成员变量和静态成员函数
一般情况下,如果有N个同类的对象,那么每一个对象都分别有自己的成员变量,不同对象的成员变量各自有值,互不相干.但是有时我们希望有某一个或几个成员变量为所有对象共有,这样可以实现数据共享. 可以使用全局 ...