UML软件工程组织

 

 

状态机工作流.实列.报销审批流程
 
作者:曲滨 来源:cnblogs
 

[本文代码下载/download]

业务描述

就是一个简单的报销单流转审批的业务

业务讲解

角色/功能
  1. 报销者

      申请、填写、修改、报销单

     
  2. 财务

      默认1000元以下金额由财务进行审核, 功能:打回(让报销者重新填写)、中止(工作流)、同意(流转到出纳)、加签(遇到特殊情况可以让老板加签就是让老板在审核一下)

     
  3. 老板

      默认 1000 元以上有老板审核,功能和财务基本一样(没加签)

     
  4. 出纳

      如果一个报销单,财务或老板审批完成有财务给钱,功能:没钱(等待,自己流转到自己),有钱(流转到取钱确认)

     
说明
除了“报销者” 都可以填写审核意见

工作流设计

明显是一个很标准的状态机的工作流

ExternalDataExchangeService 接口设计 (MyWorkflows.IBILLService.cs,MyWorkflows.IBILLService)

  由需求中可知分析出 7 种事件


具体分析
  1. 小金额

      由财务和老板的功能分析得出 (财务 默认1000元以下金额由财务进行审核,老板 默认 1000 元以上有老板审核)

     
  2. 大金额

      同上

     
  3. 打回重新修改

      财务老板都有 "打回"

     
  4. 向下流转

      这个不用说了,状态机工作流必然有的向下流转的

     
  5. 结束工作流

      财务和老板都有 "中止"

     
  6. 等待

      出纳分析得出(没钱的时候)

     
  7. 加签

      由财务业务分析得出(遇到特殊情况可以让老板加签)

     

代码 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 项目文件主要功能描述

  1. Web.Config

      配置了一些工作流服务
      WorkflowRuntime 加载的,ManualWorkflowSchedulerService 和 ExternalDataExchangeService
      ExternalDataExchangeService 加载的,上篇文章中的 MyWorkflows.BillServer

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

        }

  3. 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);
            }
        }
  4. 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);
            }
        }
  5. 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("");
                    
            //    }            
                
            }
        }
  6. Boss.aspx (老板)

      页面加载显示老板应该处理的流程,选择一个正在进行的流程进行审批,动态取得审批方式到下拉框
     
  7. PayBox.aspx (出纳)

      页面加载显示出纳应该处理的流程,选择一个正在进行的流程进行审批,动态取得审批方式到下拉框
     
  8. 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 太大计算机已经没地方安装了,
再说就算安装了也找不到英文不好基本就是小学英语水平,还有版本老更新受不了....)

  1. 在 workflowRuntime 添加自定义 WorkflowPersistenceService (在web项目里 Global.asax里有列子)
  2. 当 工作流引擎需要持久化 下面是函数的调用顺序
    UnloadOnIdle //看看持久化服务空闲不如果返回 true 继续
    SaveWorkflowInstanceState //调用保存状态寒酸
    MustCommit //看看是否需要 commit 如果返回true 继续
    Commit //提交 如果以前UnloadOnIdle 有返回 false 的时候就会多次调用 SaveWorkflowInstanceState 和 Commit 把以前没保存的也保存了
    Complete //完成通知 持久化 引擎已经完成了一个工作流的持久化

 

 

组织简介 | 联系我们 |   Copyright 2002 ®  UML软件工程组织 京ICP备10020922号

京公海网安备110108001071号