状态机工作流.实列.报销审批流程(三)
接上篇文章 “状态机工作流.实列.报销审批流程(二) ”
本文主要讲述,如何实现一个自定义的,状态保存服务,原本是要写一个保存到Oracle 数据库的,状态保存服务的、不过家里没有 Oracle ,
而且现在主要是为了练习一些实列,底层的东西是需要好好设计一下的,现在在还没有对状态保持等WF服务了解到一定的程度所以这里子凭自己的感觉,和看 ms 的代码,和一些网友的东西作也许有很多不对的地方、还需以后更正......
不过代码既然都发了还是需要写点啥的对吧.
涉及技术
WorkflowPersistenceService 的实现
对象序列化(这个没啥好讲的,打VC5 时代就有的东西,园子里也有好多文章讲解)
本文主要讲述,如何实现一个自定义的,状态保存服务,原本是要写一个保存到Oracle 数据库的,状态保存服务的、不过家里没有 Oracle ,
而且现在主要是为了练习一些实列,底层的东西是需要好好设计一下的,现在在还没有对状态保持等WF服务了解到一定的程度所以这里子凭自己的感觉,和看 ms 的代码,和一些网友的东西作也许有很多不对的地方、还需以后更正......
不过代码既然都发了还是需要写点啥的对吧.
涉及技术
WorkflowPersistenceService 的实现
对象序列化(这个没啥好讲的,打VC5 时代就有的东西,园子里也有好多文章讲解)
类设计/说明(Xom.WF.ManagerWorkflowLibrary 项目)
程序运行流程是这样的
- FileWorkflowPersistenceService
就是持久化服务了,在 web 项目 Global 里加载的,继承 WorkflowPersistenceService,实现 IPendingWork
WorkflowPersistenceService 实现
- Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity)
读取一个已经完成的 Activity(这个还不知道啥时候调用)
- Activity LoadWorkflowInstanceState(Guid instanceId)
读取一个没完成的 activity 状态
代码
/// <summary>
/// 载入实例 activity 状态
/// </summary>
/// <param name="instanceId"></param>
/// <returns></returns>
protected override System.Workflow.ComponentModel.Activity LoadWorkflowInstanceState(Guid instanceId)
{
Debug.WriteLine("LoadWorkflowInstanceState");
byte[] buffer1 = null;
FileTools.LoadActivity(_mainPath, instanceId, out buffer1);
return WorkflowPersistenceService.RestoreFromDefaultSerializedForm(buffer1, null);
}
- SaveCompletedContextActivity(Activity activity)
保存一个已经完成的 Activity(这个还不知道啥时候调用)
- SaveWorkflowInstanceState(rootActivity, bool unlock)
保存一个没完成的 Activity,在我的列子里 unlock 好像永远是 true
代码
/// <summary>
/// 保存实例
/// </summary>
/// <param name="rootActivity"></param>
/// <param name="unlock"></param>
protected override void SaveWorkflowInstanceState(System.Workflow.ComponentModel.Activity rootActivity, bool unlock)
{
Debug.WriteLine("SaveWorkflowInstanceState:" + unlock);
if (rootActivity == null)
{
throw new ArgumentNullException("rootActivity");
}
//取得当前工作流状态
WorkflowStatus status = WorkflowPersistenceService.GetWorkflowStatus(rootActivity);
//不太明白英文不好不过 ms 保存了咱也保存 (Indicates whether the given activity is blocked)
bool blocked = WorkflowPersistenceService.GetIsBlocked(rootActivity);
//停止的信息
string info = WorkflowPersistenceService.GetSuspendOrTerminateInfo(rootActivity);
//状态id
Guid stateId = (Guid)rootActivity.GetValue(Activity.ActivityContextGuidProperty);
//状态存实体类
PendingWorkItem item1 = new PendingWorkItem();
//标示,调用的是 SaveWorkflowInstanceState 函授
item1.Type = PendingWorkItem.ItemType.Instance;
//当前的 WorkflowInstanceId
item1.InstanceId = WorkflowEnvironment.WorkflowInstanceId;
byte[] buffer1;
if ((status != WorkflowStatus.Completed) && (status != WorkflowStatus.Terminated))
{//如果不是停止或出错就序列化
buffer1 = WorkflowPersistenceService.GetDefaultSerializedForm( rootActivity );
}
else
{
buffer1 = new byte[0];
}
//把一系列数据放到 PendingWorkItem
item1.SerializedActivity = buffer1;
item1.Status = (int)status;
item1.Blocked = blocked ? 1 : 0;
item1.Info = info;
item1.StateId = stateId;
item1.Unlocked = unlock;
TimerEventSubscription subscription1 = ((TimerEventSubscriptionCollection)rootActivity.GetValue(TimerEventSubscriptionCollection.TimerCollectionProperty)).Peek();
item1.NextTimer = (subscription1 == null) ? DateTime.MaxValue : ((DateTime)subscription1.ExpiresAt);
if (item1.Info == null)
{
item1.Info = "";
}
//放到 WorkBatch 里,由于实现了 IPendingWork 所以可以把你的自定义实体类放到 WorkBatch 中
//等 UnloadOnIdle 返回 true 时会调用 IPendingWork.Commit 统一处理
WorkflowEnvironment.WorkBatch.Add(this, item1);
}
- bool UnloadOnIdle(System.Workflow.ComponentModel.Activity activity)
询问持久化服务是否空闲,是否可以重内存中卸载工作流到持久化,我的代码始终是true 的
- UnlockWorkflowInstanceState(System.Workflow.ComponentModel.Activity rootActivity)
解锁一个正在运行的工作流,****这个我发的代码里处理是不对的,我把他给按Completed 处理的大家注意***
IPendingWork 接口实现
类中的其他函数
- Commit(System.Transactions.Transaction transaction, System.Collections.ICollection items)
当 UnloadOnIdle 为 true 时会执行本操作,进行序列化如果不实现 IPendingWork 应该在 SaveWorkflowInstanceState 里直接保存
代码
public void Commit(System.Transactions.Transaction transaction, System.Collections.ICollection items)
{
Debug.WriteLine("Commit");
foreach (PendingWorkItem item1 in items)
{
switch (item1.Type)
{
case PendingWorkItem.ItemType.Instance:
{//
if (item1.Status == 1 || item1.Status == 3)
{//Completed or Terminated
//如果是出错或完成的就更名为 .bak 文件
FileTools.BakPendingWorkItem(this._mainPath, item1.InstanceId);
}
else
{//如果是正常的工作流 就保存为 ,<Guid>.xact 文件名方式保存到 MainPath 中
FileTools.SavePendingWorkItem(this._mainPath, item1);
}
break;
}
case PendingWorkItem.ItemType.CompletedScope:
{
throw new ApplicationException("Commit case PendingWorkItem.ItemType.CompletedScope");
}
case PendingWorkItem.ItemType.ActivationComplete:
{
FileTools.BakPendingWorkItem(this._mainPath,item1.InstanceId); //这里的处理是不正确的应该是解锁我以前理解错了
break;
}
}
//
}
}
- Complete(bool succeeded, System.Collections.ICollection items)
持久化完成
- bool MustCommit(System.Collections.ICollection items)
是否需要 commit,我的代码里始终是 true
- 构造函数
没啥就是取了一个 保存的路径,实现了 FileWorkflowPersistenceService(NameValueCollection parameters) 就可以重配置文件传参数了- GetAllWorkflows()
取得所有没完成的 Activity 就是循环目录里所有的 *.xact
- FileTools
这个文件都是一些序列化或反序列化的函授方法不再详细说明了,各位也都能看懂估计
- PendingWorkItem
状态保存用的实体类,就是保存些数据啥的,看ms 代码得来的
代码
/// <summary>
/// 保持状态的模块类
/// </summary>
[Serializable]
public sealed class PendingWorkItem
{
// Methods
public PendingWorkItem()
{
}
//看提示是 Indicates whether the given activity is blocked. 不知道啥意识不过ms 写了咱也留着
public int Blocked;
//信息
public string Info;
//工作流运行时的 Guid
public Guid InstanceId;
public DateTime NextTimer;
//序列化的工作流
public byte[] SerializedActivity = new byte[0];
//
public Guid StateId;
//工作流的状态Guid
public int Status;
//状态,标示是调用的那个 WorkflowPersistenceService 的函数
public ItemType Type;
//是否是锁定的
public bool Unlocked;
[Serializable]
public enum ItemType
{
Instance, //正常的状态
CompletedScope, //完成
ActivationComplete //激活
}
}
(自己的见解,不是官方的,Windows SDK 太大计算机已经没地方安装了,
再说就算安装了也找不到英文不好基本就是小学英语水平,还有版本老更新受不了....)
- 在 workflowRuntime 添加自定义 WorkflowPersistenceService (在web项目里 Global.asax里有列子)
- 当 工作流引擎需要持久化 下面是函数的调用顺序
UnloadOnIdle //看看持久化服务空闲不如果返回 true 继续
SaveWorkflowInstanceState //调用保存状态寒酸
MustCommit //看看是否需要 commit 如果返回true 继续
Commit //提交 如果以前UnloadOnIdle 有返回 false 的时候就会多次调用 SaveWorkflowInstanceState 和 Commit 把以前没保存的也保存了
Complete //完成通知 持久化 引擎已经完成了一个工作流的持久化其他没写在上面的代码都是大同小异的