[本文代码下载/download]
业务描述
就是一个简单的报销单流转审批的业务
业务讲解
角色/功能
- 报销者
申请、填写、修改、报销单
- 财务
默认1000元以下金额由财务进行审核, 功能:打回(让报销者重新填写)、中止(工作流)、同意(流转到出纳)、加签(遇到特殊情况可以让老板加签就是让老板在审核一下)
- 老板
默认 1000 元以上有老板审核,功能和财务基本一样(没加签)
- 出纳
如果一个报销单,财务或老板审批完成有财务给钱,功能:没钱(等待,自己流转到自己),有钱(流转到取钱确认)
说明
除了“报销者” 都可以填写审核意见
工作流设计
明显是一个很标准的状态机的工作流
ExternalDataExchangeService 接口设计 (MyWorkflows.IBILLService.cs,MyWorkflows.IBILLService)
由需求中可知分析出 7 种事件
具体分析
- 小金额
由财务和老板的功能分析得出 (财务 默认1000元以下金额由财务进行审核,老板 默认 1000
元以上有老板审核)
- 大金额
同上
- 打回重新修改
财务老板都有 "打回"
- 向下流转
这个不用说了,状态机工作流必然有的向下流转的
- 结束工作流
财务和老板都有 "中止"
- 等待
出纳分析得出(没钱的时候)
- 加签
由财务业务分析得出(遇到特殊情况可以让老板加签)
代码 IBILLService 工作流设计时使用
[ExternalDataExchange]
public interface IBILLService
{
/// <summary>
/// 小金额
/// </summary>
event EventHandler<ExternalDataEventArgs> BillInitMoneyMin;
/// <summary>
/// 大金额
/// </summary>
event EventHandler<ExternalDataEventArgs> BillInitMoneyMax;
/// <summary>
/// 打回重新修改
/// </summary>
event EventHandler<ExternalDataEventArgs> BillUpdated;
/// <summary>
/// 向下流转
/// </summary>
event EventHandler<ExternalDataEventArgs> BillNext;
/// <summary>
/// 结束工作流
/// </summary>
event EventHandler<ExternalDataEventArgs> BillCanceled;
/// <summary>
/// 等待
/// </summary>
event EventHandler<ExternalDataEventArgs> BillWait;
/// <summary>
/// 加签
/// </summary>
event EventHandler<ExternalDataEventArgs> BillInsert;
} |
代码 IBILLService 的实现 BillServer
(也在 IBILLService)
/// <summary>
/// IBILLService 实现,本类在 web项目 <ExternalDataExchangeService/> 节配置加载
/// </summary>
[Serializable]
public class BillServer : IBILLService
{
public BillServer()
{
System.Diagnostics.Debug.WriteLine("Create OrderService");
}
/// <summary>
/// 事件检索字典(不一定非要这么设计,不过个人感觉这么方便触发事件比较简单而且容易被配置化)
/// 不过这么做事件子可以被映射一次如果需要映射多次自己改
/// </summary>
Dictionary<string, EventHandler<ExternalDataEventArgs>> _EventList
= new Dictionary<string, EventHandler<ExternalDataEventArgs>>();
/// <summary>
/// 事件触发函数
/// </summary>
/// <param name="name"></param>
/// <param name="instanceId"></param>
public void RaiseEvent(string name, Guid instanceId)
{
if (_EventList[name] != null)
{
EventHandler<ExternalDataEventArgs> eventHand = _EventList[name];
ExternalDataEventArgs ede = new ExternalDataEventArgs(instanceId);
//ede.WorkItem = parms;
eventHand(this, ede);
}
}
#region IBILLService 成员
public event EventHandler<ExternalDataEventArgs> BillInitMoneyMin
{
add
{
_EventList.Add("BillInitMoneyMin", value);
}
remove
{
_EventList.Remove("BillInitMoneyMin");
}
}
public event EventHandler<ExternalDataEventArgs> BillInitMoneyMax
{
add
{
_EventList.Add("BillInitMoneyMax", value);
}
remove
{
_EventList.Remove("BillInitMoneyMax");
}
}
public event EventHandler<ExternalDataEventArgs> BillUpdated
{
add
{
_EventList.Add("BillUpdated",value);
}
remove
{
_EventList.Remove("BillUpdated");
}
}
public event EventHandler<ExternalDataEventArgs> BillNext
{
add
{
_EventList.Add("BillNext", value);
}
remove
{
_EventList.Remove("BillNext");
}
}
public event EventHandler<ExternalDataEventArgs> BillCanceled
{
add
{
_EventList.Add("BillCanceled", value);
}
remove
{
_EventList.Remove("BillCanceled");
}
}
public event EventHandler<ExternalDataEventArgs> BillWait
{
add
{
_EventList.Add("BillWait", value);
}
remove
{
_EventList.Remove("BillWait");
}
}
public event EventHandler<ExternalDataEventArgs> BillInsert
{
add
{
_EventList.Add("BillInsert", value);
}
remove
{
_EventList.Remove("BillInsert");
}
}
#endregion
} |
正常业务不可能没其他数据的虚拟了一个数据实体类保存,报销金额啥的
BillModel (也在 IBILLService)
[Serializable]
public class BillModel
{
string _userName;
/// <summary>
/// 报销人
/// </summary>
public string UserName
{
get { return _userName; }
set { _userName = value; }
}
string _billId;
/// <summary>
/// 报销编号,数据库里的
/// </summary>
public string BillId
{
get { return _billId; }
set { _billId = value; }
}
decimal _money;
/// <summary>
/// 报销金额
/// </summary>
public decimal Money
{
get { return _money; }
set { _money = value; }
}
private string fremark;
/// <summary>
/// 财务批示
/// </summary>
public string Fremark
{
get { return fremark; }
set { fremark = value; }
}
private string bremark;
/// <summary>
/// 老板批示
/// </summary>
public string Bremark
{
get { return bremark; }
set { bremark = value; }
}
private string premark;
/// <summary>
/// 出纳批示
/// </summary>
public string Premark
{
get { return premark; }
set { premark = value; }
}
private string lastRemark;
/// <summary>
/// 最后批示
/// </summary>
public string LastRemark
{
get { return lastRemark; }
set { lastRemark = value; }
}
} |
工作流设计 (MyWorkflows.BillWorkflow.cs)
上图中的所有 EventDrivenActivity 里面都子有一个 HandleExternalEventActivity(外部事件)
和一个 SetStateActivity(设置流转)
一下说明工作流和 IBILLService 的对应关系
stateInit/eveTo01 对应 BillInitMoneyMin
stateInit/eveTo01 对应 BillInitMoneyMax
statePayBox/eveWait 对应 BillWait
其他名称(name)是OK 的如 eveomOk,evePok 等对应 BillNext
是 Update 的对应 BillUpdated
是 BillCanceled 对应 BillCanceled
还有一个加签在以后代码中\动态加入,不再设计器中表现
涉及技术
在Web.config 配置
取得工作流结构
动态加签
动态取得审批方式
启动工作流流转等(这个好多列子中都有不再详细描述)
Web 项目文件主要功能描述
- Web.Config
配置了一些工作流服务
WorkflowRuntime 加载的,ManualWorkflowSchedulerService
和 ExternalDataExchangeService
ExternalDataExchangeService 加载的,上篇文章中的 MyWorkflows.BillServer
- Global.asax,App_Code\Global.asax.cs
启动 WorkflowRuntime,加载 FileWorkflowPersistenceService(自定义的状态保存服务,下篇文章详细讲解)
代码
protected void Application_Start(object sender, EventArgs e)
{
Console.WriteLine("Application_Start:");
System.Workflow.Runtime.WorkflowRuntime workflowRuntime =
new System.Workflow.Runtime.WorkflowRuntime(MyWorkHelpr.WorkflowRuntimeName);
//加载状态保持服务(自己的类),构造函数设置保存状态的路径
FileWorkflowPersistenceService f28s =
new FileWorkflowPersistenceService(Server.MapPath("~/App_Data/XOM.WFDB/"));
workflowRuntime.AddService(f28s);
Application[MyWorkHelpr.WorkflowRuntimeName] = workflowRuntime;
//映射事件没用上
workflowRuntime.WorkflowCompleted +=
new EventHandler<System.Workflow.Runtime.WorkflowCompletedEventArgs>(workflowRuntime_WorkflowCompleted);
workflowRuntime.WorkflowTerminated +=
new EventHandler<System.Workflow.Runtime.WorkflowTerminatedEventArgs>(workflowRuntime_WorkflowTerminated);
workflowRuntime.WorkflowSuspended +=
new EventHandler<System.Workflow.Runtime.WorkflowSuspendedEventArgs>(workflowRuntime_WorkflowSuspended);
workflowRuntime.WorkflowPersisted +=
new EventHandler<System.Workflow.Runtime.WorkflowEventArgs>(workflowRuntime_WorkflowPersisted);
workflowRuntime.StartRuntime();
//重状态保存读取所有没执行完的了类.
foreach (Guid id in f28s.GetAllWorkflows())
{
workflowRuntime.GetWorkflow(id);
}
} |
- Default.aspx (用户登陆)
导航页面,可以模拟各种角色登陆,可以显示全部正在进行的工作流信息、可以查看工作流的结构
代码说明
取得工作流结构
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
int i = 0;
if (e.CommandName.ToLower() == "select")
{//就想取两级就不递归了
i = Convert.ToInt32(e.CommandArgument);
string sguid = GridView1.Rows[i].Cells[1].Text.Trim();
Guid instanceId = new Guid(sguid);
WorkflowInstance workInstance = (Application
[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetWorkflow(instanceId);
StateMachineWorkflowActivity MainActivity =
workInstance.GetWorkflowDefinition() as StateMachineWorkflowActivity;
TreeView1.Nodes.Clear();
TreeNode MainNode = new TreeNode();
TreeNode NodeL1 = null;
TreeNode NodeL2 = null;
MainNode.Text = sguid;
foreach(StateActivity state in MainActivity.Activities)
{
NodeL1 = new TreeNode();
NodeL1.NavigateUrl="#";
NodeL1.Text = state.Name + ":" +state.Description;
foreach(CompositeActivity cactive in state.Activities)
{
NodeL2 = new TreeNode();
NodeL2.NavigateUrl = "#";
NodeL2.Text = cactive.Name + ":" + cactive.Description;
NodeL1.ChildNodes.Add(NodeL2);
}
MainNode.ChildNodes.Add(NodeL1);
}
MainNode.ExpandAll();
TreeView1.Nodes.Add(MainNode);
//btnReadGuid_Click(btnReadGuid, null);
}
} |
- CreateBill.aspx (创建修改报销单)
填写表单,根据金额判断跳转到老板,还是财务(跳转是在ASP.net程序中控制的,其实也可以在工作流里控制,有情趣的可以自己改改)
代码
protected void btnOk_Click(object sender, EventArgs e)
{
if(TextBox1.Text.Length>0)
{
Guid InstanceId = new Guid(TextBox1.Text);
BillServer billserver = (Application
[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetService<BillServer>();
ManualWorkflowSchedulerService scheduler =
(Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetService<ManualWorkflowSchedulerService>();
decimal money = decimal.Parse(txt3.Text);
if (money < 1) return;
string wsPath = HttpContext.Current.Server.MapPath("~/App_Data/WorkflowSave/");
//如果已经有数据取得
BillModel model = FileTools.XmlDeserializeObject(wsPath
, InstanceId
, typeof(BillModel)) as BillModel;
if (model==null) model = new BillModel();
model.BillId = txt1.Text;
model.Money = money;
model.UserName = txt2.Text;
if(model.Money > 1000)
{//流转到老板
billserver.RaiseEvent("BillInitMoneyMax", InstanceId);
}
else
{//流转到财务
billserver.RaiseEvent("BillInitMoneyMin",InstanceId);
}
//流转工作流
scheduler.RunWorkflow(InstanceId);
TextBox1.Text="";
//保存更改的数据
FileTools.XmlSerializeObject(wsPath
, InstanceId
, model);
//this.Response.Redirect("default.aspx", false);
}
} |
- Finance.aspx (财务)
页面加载显示财务应该处理的流程,选择一个正在进行的流程进行审批,动态取得审批方式到下拉框(审批方式是工作流设计器上设计的)、如果需要可以动态增加一个老板加签
代码说明
动态取得审批方式到下拉框的代码
protected void btnReadGuid_Click(object sender, EventArgs e)
{
string s = txtGuid.Text.Trim();
if(s.Length>0)
{
Guid instanceId = new Guid(s);
//取得当前工作流里正在进行的 StateMachineWorkflow (这里是 stateFinance)
StateMachineWorkflowInstance stateInstance =new StateMachineWorkflowInstance
(Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime, instanceId);
using(DataTable dt = new DataTable())
{
//创建一个下拉框用的 DataTable
dt.Columns.Add("NID", typeof(string)); //保存 EventDrivenActivity 的名字,在确定时使用
dt.Columns.Add("NTEXT", typeof(string)); //保存 EventDrivenActivity 的说明
dt.Rows.Add("-1","==请选择==");
int i=0;
foreach(Activity act in stateInstance.CurrentState.EnabledActivities)
{//循环当前流程可以用的 Activitie (在本步骤就是设计器里的 stateFinance 中的那些 EventDrivenActivity)
if (act is EventDrivenActivity )
{
EventDrivenActivity edact = (EventDrivenActivity)act;
if (edact.EnabledActivities.Count >0 && edact.EnabledActivities[0] is HandleExternalEventActivity)
{//取得每个 EventDrivenActivity 中第一个 HandleExternalEventActivity 把名字和说明放到 dt 中
dt.Rows.Add(edact.Name, act.Description);
}
}
i++;
}
//DataBind
DropDownList1.DataValueField = "NID";
DropDownList1.DataTextField = "NTEXT";
DropDownList1.DataSource = dt;
DropDownList1.DataBind();
}
}
} |
动态加签的代码
protected void Button2_Click(object sender, EventArgs e)
{
string s = txtGuid.Text.Trim();
if(s.Length>0)
{
Guid instanceId = new Guid(s);
WorkflowInstance workInstance = (Application
[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetWorkflow(instanceId);
//取得整个工作流对象
StateMachineWorkflowActivity activity =
(StateMachineWorkflowActivity)workInstance.GetWorkflowDefinition();
//用 WorkflowChanges 榜定 activity
WorkflowChanges wfc = new WorkflowChanges(activity);
//取得财务的 StateActivity
StateActivity state =
(StateActivity)wfc.TransientWorkflow.Activities["stateFinance"];
if(state.Activities["eveToBoss"]!= null ) return;
//声明一个外部事件
HandleExternalEventActivity externalEveTmp = new HandleExternalEventActivity();
externalEveTmp.EventName = "BillInsert";
externalEveTmp.InterfaceType = typeof(MyWorkflows.IBILLService);
externalEveTmp.Name = "externalEveTmp";
//设置一个跳转
SetStateActivity setActTmp = new SetStateActivity();
setActTmp.Name = "setActTmp";
setActTmp.TargetStateName = "stateBoss";
EventDrivenActivity EventDrivenTmp = new EventDrivenActivity();
EventDrivenTmp.Activities.Add(externalEveTmp);
EventDrivenTmp.Activities.Add(setActTmp);
EventDrivenTmp.Description = "*老板加签*";
EventDrivenTmp.Name = "eveToBoss";
//挂起
workInstance.Suspend("正在加签");
//财务的 StateActivity 中加入一个 EventDrivenActivity
state.Activities.Add(EventDrivenTmp);
ValidationErrorCollection err = wfc.Validate();
//应用更改
workInstance.ApplyWorkflowChanges(wfc);
//恢复
workInstance.Resume();
btnReadGuid_Click(btnReadGuid,new EventArgs());
}
} |
确定按扭时使用 下拉框 里的审批方式
protected void Button1_Click(object sender, EventArgs e)
{
string s = txtGuid.Text.Trim();
if (s.Length > 0 && DropDownList1.SelectedValue != "-1")
{
//取得下拉框选择的 value btnReadGuid_Click 中取得的
string nid = DropDownList1.SelectedValue;
Guid instanceId = new Guid(s);
BillServer billserver = (Application[MyWorkHelpr.WorkflowRuntimeName]
as WorkflowRuntime).GetService<BillServer>();
ManualWorkflowSchedulerService scheduler = (Application[MyWorkHelpr.WorkflowRuntimeName]
as WorkflowRuntime).GetService<ManualWorkflowSchedulerService>();
StateMachineWorkflowInstance stateInstance = new StateMachineWorkflowInstance
(Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime, instanceId);
//通过名称取得 EventDrivenActivity
EventDrivenActivity edact = (EventDrivenActivity)stateInstance.CurrentState.Activities[nid];
//和第一个 HandleExternalEventActivity
HandleExternalEventActivity heva = (HandleExternalEventActivity)edact.EnabledActivities[0];
//WorkflowInstance workInstance = stateInstance.WorkflowInstance;
//BillWorkflow act = stateInstance.WorkflowInstance.GetWorkflowDefinition() as BillWorkflow;
string wsPath = HttpContext.Current.Server.MapPath("~/App_Data/WorkflowSave/");
BillModel model = FileTools.XmlDeserializeObject(wsPath
, instanceId
, typeof(BillModel)) as BillModel;
model.LastRemark = model.Fremark = string.Concat("财务: ",
DropDownList1.SelectedItem.Text, ":", txtRemark.Text);
//通过 HandleExternalEventActivity.EventName 调用 BillServer.RaiseEvent 触发外部事件使工作流向前运行
//这就是我为上一章何在 BillServer 重写那些事件的原因
billserver.RaiseEvent(heva.EventName, instanceId);
//工作流向下流转
scheduler.RunWorkflow(instanceId);
FileTools.XmlSerializeObject(wsPath,instanceId,model);
DropDownList1.Items.Clear();
txtGuid.Text = "";
//stateInstance.CurrentStateName
return;
// //如果用过一次要删除
// if(edact.Name == "eveToBoss") //删除加签
// {
// //WorkflowInstance workInstance = (Application[MyWorkHelpr.WorkflowRuntimeName]
as WorkflowRuntime).GetWorkflow(instanceId);
// workInstance.Suspend("正在删除加签");
// StateMachineWorkflowActivity activity =
workInstance.GetWorkflowDefinition() as StateMachineWorkflowActivity;
// WorkflowChanges wfc = new WorkflowChanges(activity);
// //StateActivity sa = wfc.TransientWorkflow.Activities["stateFinance"] as StateActivity;
// StateActivity state = (StateActivity)wfc.TransientWorkflow.Activities["stateFinance"];
// state.Activities.Remove(state.Activities["eveToBoss"]);
// ValidationErrorCollection err = wfc.Validate();
// workInstance.ApplyWorkflowChanges(wfc);
// workInstance.Resume();
// //this.Response.Redirect("");
// }
}
} |
- Boss.aspx (老板)
页面加载显示老板应该处理的流程,选择一个正在进行的流程进行审批,动态取得审批方式到下拉框
- PayBox.aspx (出纳)
页面加载显示出纳应该处理的流程,选择一个正在进行的流程进行审批,动态取得审批方式到下拉框
- OutMoney.aspx(取钱确认)
页面加载子显示出纳审批Ok 的流程,选择一个正在进行的流程确认以读取,动态取得审批方式到下拉框
说明
其实重财务以后的页面处理方式都基本是一样的,界面也都类似,不再多说...
本文主要讲述,如何实现一个自定义的,状态保存服务,原本是要写一个保存到Oracle 数据库的,状态保存服务的、不过家里没有 Oracle
,
而且现在主要是为了练习一些实列,底层的东西是需要好好设计一下的,现在在还没有对状态保持等WF服务了解到一定的程度所以这里子凭自己的感觉,和看
ms 的代码,和一些网友的东西作也许有很多不对的地方、还需以后更正......
不过代码既然都发了还是需要写点啥的对吧.
涉及技术
WorkflowPersistenceService 的实现
对象序列化(这个没啥好讲的,打VC5 时代就有的东西,园子里也有好多文章讲解)
类设计/说明(Xom.WF.ManagerWorkflowLibrary 项目)
1.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
2.FileTools
这个文件都是一些序列化或反序列化的函授方法不再详细说明了,各位也都能看懂估计
3.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 //完成通知 持久化 引擎已经完成了一个工作流的持久化
|