上篇 Asp.Net 中的报销多级审批工作流 ,提到参考了网上一个具体的项目,项目中用状态机工作流完成,基于学习的原因,我采用顺序工作流,事件驱动方式实现了同样的功能。后来学习到了状态机,觉的状态机实现也特别方便。 下面我分享下状态机工作流中几个主要的活动。

顺序工作流与状态机工作流的区别:

顺序工作流是一种可以预测,流程比较固定,而状态机工作流不可预测,主要靠外部事件驱动来实现,对外的交互比较多,系统的状态需要外部事件的触发来改变。

      状态机工作流活动图:

附件: 2009-2-27-1.jpg


      1:State Activity,在状态机工作流中代表了一个具体的状态,这种状态机以事件驱动为主,和之前顺序工作流中的事件驱动有点类似。在整个状态机工作流中,会有一个初始化的State Activity和一个表示完成的State Activity,我们从工具箱中拉一个State Activity,然后单击右键,出现如下图,绿色的表示初始化State Activity,而红色的表示完成的State Activity,分别会在State Activity的左上角有相应的标示。

附件: 2009-2-27-2.jpg

      2:EventDriven Activity,做为State Activity的子活动,状态中的所有事件都存放在这。

      3:HandleExternalEvent activity,这就是具体的外部事件活动,它即可以用在顺序工作流中,也可以用在状态机工作流中。设置方法可参考上篇文章asp.net中的报销多级审批工作流。

      4:SetState Activity,外部事件的执行会使状态机工作流中的状态发生变化,说的通俗点就是告诉状态机下一步的动向。我们只要设置它的一个关键属性就行:TargetStateName,这个属性是指向状态机中一个已经存在的具体状态。设置好后就会发生在设计器中出现连接箭头。

      宿主调用代码的封装:

          我发现源项目中没有封装对于WorkflowRuntime和WorkflowInstance的使用,每个审批页面都会出现很多初始化工作流引擎, 创建工作流实例的代码,这里我在公共层中封装了一个WorkflowWrapper类。主要方法有:

        1:InitWorkFlowRuntime,初始化工作流引擎。

        2:StartWorkFlowRuntime,启动工作流引擎。

        3:OnWorkflowIdled,工作流闲置事件。

        4:CreateWorkFlowInstance,创建一个工作流实例。

        5:GetWorkflowInstance,返回一个工作流实例。

        6:StartWorkFlowInstance,启动工作流实例。

        7:GetGetWorkflowById,加载一个已经存在的未完成的工作流实例。

        8:Dispose,释放资源。

      WorkflowWrapper类详细代码如下:
  1. public  class WorkflowWrapper:IDisposable
  2.     {
  3.         static WorkflowRuntime runtime;//运行时
  4.         static  WorkflowInstance instance;//实例
  5.         static ExternalDataExchangeService service;//外部数据交换服务
  6.         static WorkflowPersistenceService perService;//持久化服务
  7.         public static  BLL_Approve project;//实现接口类
  8.       /// <summary>
  9.       /// 启动工作流引擎
  10.       /// </summary>
  11.         public void StartWorkFlowRuntime()
  12.         {
  13.             if (runtime != null)
  14.             {
  15.                 try
  16.                 {
  17.                     //启动工作流引擎
  18.                     runtime.StartRuntime();
  19.                 }
  20.                 catch(Exception ex)
  21.                 {
  22.                     this.InitWorkFlowRuntime();
  23.                 }
  24.             }
  25.             else
  26.             {
  27.                 this.InitWorkFlowRuntime();
  28.             }
  29.         }
  30.       /// <summary>
  31.       /// 初始化工作流引擎
  32.       /// </summary>
  33.         public void InitWorkFlowRuntime()
  34.         {       
  35.             runtime = new WorkflowRuntime();
  36.             service = new ExternalDataExchangeService();
  37.             project = new BLL_Approve();

  38.             perService = new SqlWorkflowPersistenceService(ConfigurationManager.

  39.             ConnectionStrings["perstr"].ConnectionString);

  40.             if (runtime.GetService(service.GetType()) == null)//服务不能重复加入
  41.             {
  42.                 runtime.AddService(service);
  43.             }
  44.             if (runtime.GetService(perService.GetType()) == null)
  45.             {
  46.                 //加入持久化服务
  47.                 runtime.AddService(perService);
  48.             }
  49.             if (service.GetService(project.GetType()) == null)
  50.             {
  51.                 //将此类加入外部数据交换服务
  52.                 service.AddService(project);
  53.             }
  54.             //工作流闲置事件
  55.             runtime.WorkflowIdled += OnWorkflowIdled;
  56.             //启动工作流引擎
  57.             runtime.StartRuntime();
  58.         }
  59.       /// <summary>
  60.       /// 工作流闲置事件
  61.       /// </summary>
  62.       /// <param name="sender"></param>
  63.       /// <param name="e"></param>
  64.         private  void OnWorkflowIdled(object sender, WorkflowEventArgs e)
  65.         {
  66.             e.WorkflowInstance.TryUnload();//将内存数据持久化到数据库中
  67.         }
  68.       /// <summary>
  69.       /// 创建一个工作流实例
  70.       /// </summary>
  71.         public void CreateWorkFlowInstance()
  72.         {
  73.             //确保启动了工作流引擎
  74.             this.StartWorkFlowRuntime();
  75.             //创建一个工作流实例

  76.             string sWorkFlowType =

  77.             ConfigurationManager.AppSettings["WorkFlowType"].Trim();

  78.             switch (sWorkFlowType)
  79.             {
  80.                 case "1":

  81.                     instance = runtime.CreateWorkflow(typeof(

  82.                     ApproveWorkFlow.MyWorkFlow.Workflow1));

  83.                     break;
  84.                 case "2":

  85.                     instance = runtime.CreateWorkflow(typeof(

  86.                     ApproveWorkFlow.MyWorkFlowStateMachine .Workflow1));

  87.                     break;
  88.             }         
  89.         }
  90.       /// <summary>
  91.       /// 返回一个工作流实例
  92.       /// </summary>
  93.       /// <returns></returns>
  94.         public WorkflowInstance GetWorkflowInstance()
  95.         {
  96.             if (instance == null)
  97.             {
  98.                 this.CreateWorkFlowInstance();
  99.             }         
  100.             return instance;         
  101.         }
  102.       /// <summary>
  103.       /// 启动工作流实例
  104.       /// </summary>
  105.         public void StartWorkFlowInstance()
  106.         {
  107.             this.CreateWorkFlowInstance();
  108.             instance.Start();
  109.         }
  110.       /// <summary>
  111.       /// 加载一个已经存在的未完成的工作流实例
  112.       /// </summary>
  113.       /// <param name="_Guid"></param>
  114.         public WorkflowInstance  GetGetWorkflowById(Guid _Guid)
  115.         {
  116.             //确保启动了工作流引擎
  117.             this.StartWorkFlowRuntime();
  118.             return  runtime.GetWorkflow(_Guid);
  119.         }
  120.       /// <summary>
  121.       /// 释放资源
  122.       /// </summary>
  123.         public void Dispose()
  124.         {
  125.             if (runtime != null)
  126.             {
  127.                 //停止工作流引擎
  128.                 runtime.StopRuntime();
  129.                 //释放占用的资源
  130.                 runtime.Dispose();
  131.             }                   
  132.         }   
  133.     }
复制代码
小结:无论是之前的顺序工作流还是现在的状态机工作流,都是事件驱动性工作流,外部调用上没有任何区别,唯一的区别就在创建工作流实例,我们看下上面的创建工作流实例的方法,为了演示方便,我在web.config文件中加了一个配置节,用来控制创建的工作流类型:

<!--工作流类型 1:顺序工作流 2:状态机工作流-->
    <add key ="WorkFlowType" value ="2"/>

        经过这样的封装后我们来看下页面层的代码:页面中只会出现业务逻辑层的类,WorkFlow相关的类尽量不要直接出现,代码的复用也得到了提高,第二部分为提交事件的代码:
  1.       BllExpense Bll;
  2.         static  WorkflowWrapper _WorkflowWrapper = new WorkflowWrapper();
  3.         protected void Page_Load(object sender, EventArgs e)
  4.         {           
  5.             Bll = new BllExpense();
  6.             if (!IsPostBack)
  7.             {
  8.                 ViewState["userName"] = Request["name"];
  9.                 this.tbName.Text = ViewState["userName"].ToString();
  10.                 BindData(ViewState["userName"].ToString());               
  11.             }
  12.             //初始化,启动工作流引擎
  13.             _WorkflowWrapper.StartWorkFlowRuntime();

  14.         }
复制代码
用户的提交事件代码:
  1.   Guid workflowId = new Guid(this.tbNo.Text);
  2.                 //读取一个未完成的工作流实例

  3.                 WorkflowInstance _WorkflowInstance=

  4.               _WorkflowWrapper.GetGetWorkflowById(workflowId);

  5.                 ExpenseAccountInfo info = new ExpenseAccountInfo(                            workflowId, Convert.ToDecimal(this.tbMoney.Text),

  6. this.tbName.Text, DateTime.Now.ToShortDateString(),

  7. "结束", this.tbNotes.Text);

  8.                 //触发工作流事件

  9.                 WorkflowWrapper.project.RaiseStaffDelete(info);

  10.               //从数据库中查找作流,并加入内存中(持久化的作用)

  11.                 _WorkflowInstance.TryUnload();
  12.                 //释放资源
  13.                 _WorkflowWrapper.Dispose();
复制代码
(文/ASPNET2008

项目代码下载:
TOP