首页 > 编程语言 >asp.net中的报销多级审批工作流 (状态机版本)

asp.net中的报销多级审批工作流 (状态机版本)

时间:2022-11-27 11:39:06浏览次数:44  
标签:asp WorkflowWrapper 状态机 工作 实例 Activity net runtime


asp.net中的报销多级审批工作流 (状态机版本)


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

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

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

      状态机工作流活动图:

asp.net中的报销多级审批工作流 (状态机版本)_.net

 

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

asp.net中的报销多级审批工作流 (状态机版本)_.net_02

 

      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类详细代码如下:

 

public    class  WorkflowWrapper:IDisposable
    {
         static  WorkflowRuntime runtime; // 运行时
         static   WorkflowInstance instance; // 实例
         static  ExternalDataExchangeService service; // 外部数据交换服务
         static  WorkflowPersistenceService perService; // 持久化服务
         public   static   BLL_Approve project; // 实现接口类
        ///   <summary>
        ///  启动工作流引擎
        ///   </summary>
         public   void  StartWorkFlowRuntime()
        {
             if  (runtime  !=   null )
            {
                 try
                {
                     // 启动工作流引擎
                    runtime.StartRuntime();
                }
                 catch (Exception ex)
                {
                     this .InitWorkFlowRuntime();
                }
            }
             else
            {
                 this .InitWorkFlowRuntime();
            }
        }
        ///   <summary>
        ///  初始化工作流引擎
        ///   </summary>
         public   void  InitWorkFlowRuntime()
        {         
            runtime  =   new  WorkflowRuntime();
            service  =   new  ExternalDataExchangeService();
            project  =   new  BLL_Approve();

            perService = new SqlWorkflowPersistenceService(ConfigurationManager.

ConnectionStrings["perstr"].ConnectionString);

            if

 (runtime.GetService(service.GetType())  ==   null ) // 服务不能重复加入

            {

                runtime.AddService(service);

            }

             if  (runtime.GetService(perService.GetType()) 

==   null )

            {

                 // 加入持久化服务


                runtime.AddService(perService);

            }

             if  (service.GetService(project.GetType()) 

==   null )

            {

                 // 将此类加入外部数据交换服务


                service.AddService(project);

            }

             // 工作流闲置事件


            runtime.WorkflowIdled  +=  OnWorkflowIdled;

             // 启动工作流引擎


            runtime.StartRuntime();

        }

        ///  

<summary>

        ///  工作流闲置事件

        ///  

</summary>

        ///  

<param name="sender"></param>

        ///  

<param name="e"></param>

         private    void  OnWorkflowIdled( object  sender, WorkflowEventArgs e)

        {

            e.WorkflowInstance.TryUnload(); // 将内存数据持久化到数据库中


        }

        ///  

<summary>

        ///  创建一个工作流实例

        ///  

</summary>

         public   void  CreateWorkFlowInstance()

        {

             // 确保启动了工作流引擎


             this .StartWorkFlowRuntime();

             // 创建一个工作流实例



            string sWorkFlowType = 

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

            switch

 (sWorkFlowType)

            {

                 case  

" 1 " :


                    instance = runtime.CreateWorkflow(typeof(

ApproveWorkFlow.MyWorkFlow.Workflow1));

                    break

;

                 case  

" 2 " :


                    instance = runtime.CreateWorkflow(typeof(

ApproveWorkFlow.MyWorkFlowStateMachine .Workflow1));

                    break

;

            }         

        }

        ///  

<summary>

        ///  返回一个工作流实例

        ///  

</summary>

        ///  

<returns></returns>

         public  WorkflowInstance GetWorkflowInstance()

        {

             if  (instance 

==   null )

            {

                 this .CreateWorkFlowInstance();

            }          

             return  instance;          

        }

        ///  

<summary>

        ///  启动工作流实例

        ///  

</summary>

         public   void  StartWorkFlowInstance()

        {

             this .CreateWorkFlowInstance();

            instance.Start();

        }

        ///  

<summary>

        ///  加载一个已经存在的未完成的工作流实例

        ///  

</summary>

        ///  

<param name="_Guid"></param>

         public  WorkflowInstance  GetGetWorkflowById(Guid _Guid)

        {

             // 确保启动了工作流引擎


             this .StartWorkFlowRuntime();

             return   runtime.GetWorkflow(_Guid);

        }

        ///  

<summary>

        ///  释放资源

        ///  

</summary>

         public   void  Dispose()

        {

             if  (runtime 

!=   null )

            {

                 // 停止工作流引擎


                runtime.StopRuntime();

                 // 释放占用的资源


                runtime.Dispose();

            }                     

        }     

    }

         小结:无论是之前的顺序工作流还是现在的状态机工作流,都是事件驱动性工作流,外部调用上没有任何区别,唯一的区别就在创建工作流实例,我们看下上面的创建工作流实例的方法,为了演示方便,我在web.config文件中加了一个配置节,用来控制创建的工作流类型:


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


        经过这样的封装后我们来看下页面层的代码:页面中只会出现业务逻辑层的类,WorkFlow相关的类尽量不要直接出现,代码的复用也得到了提高,第二部分为提交事件的代码:


      BllExpense Bll;
         static   WorkflowWrapper _WorkflowWrapper  =   new  WorkflowWrapper();
         protected   void  Page_Load( object  sender, EventArgs e)
        {           
            Bll  =   new  BllExpense();
             if  ( ! IsPostBack)
            {
                ViewState[ " userName " ]  =  Request[ " name " ];
                 this .tbName.Text  =  ViewState[ " userName " ].ToString();
                BindData(ViewState[ " userName " ].ToString());               
            }
             // 初始化,启动工作流引擎
            _WorkflowWrapper.StartWorkFlowRuntime();

        }


 

           用户的提交事件代码:


  Guid workflowId  =   new  Guid( this .tbNo.Text);
                 // 读取一个未完成的工作流实例

                WorkflowInstance _WorkflowInstance= 

_WorkflowWrapper.GetGetWorkflowById(workflowId);

 


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

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

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

                //

触发工作流事件


                WorkflowWrapper.project.RaiseStaffDelete(info);

 

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

                _WorkflowInstance.TryUnload();

                 // 释放资源


                _WorkflowWrapper.Dispose();

          

标签:asp,WorkflowWrapper,状态机,工作,实例,Activity,net,runtime
From: https://blog.51cto.com/u_15834343/5889877

相关文章

  • WebClient.Credentials 属性 (System.Net)
    ​​WebClient.Credentials​​Credentials属性.NETFramework类库WebClient..::.Credentials异步下载并不会比同步下载快.它的好处是不阻塞线程,这样的你界面或其他......
  • GTK的.NET的函数库 GTK#
    Gtk#是个.NET的函数库,用来系结GTK+GUI函数库。它让你可以使用Mono或其他相容CLR的语言来开发GNOME应用程式。 Gtk#像其他现在的视窗函式库一样,采用事件驱动,让开发者可以......
  • c#.net多线程编程教学(2):Thread类
    这章将向大家介绍.NET中的线程API,怎么样用C#创建线程,启动和停止线程,设置优先级和状态.在.NET中编写的程序将被自动的分配一个线程.让我们来看......
  • WebService传输DataSet的一点想法和实践-.NET教程,Web Service开发
    其实这个标题很大,实现起来也可以有许多的办法。甚至,应否这样做也许都能惹出许多的争论(比如,为什么用ws而不是remoting?为什么传dataset而不是entity[]?)。      由于ds......
  • .NET Core中的AOP
    1.AOP的应用场景AOP全称AspectOrientedProgarmming(面向切面编程),其实AOP对ASP.NET程序员来说一点都不神秘,你也许早就通过Filter来完成一些通用的功能,例如你使用Authori......
  • Windows netstat 查看端口、进程占用
    目标:在Windows环境下,用netstat命令查看某个端口号是否占用,为哪个进程所占用.操作:操作分为两步:(1)查看该端口被那个PID所占用;方法一:有针对性的查看端口,使用命令Netstat–......
  • BT - Unet:生物医学图像分割的自监督学习框架
    BT-Unet采用Barlowtwin方法对U-Net模型的编码器进行无监督的预训练减少冗余信息,以学习数据表示。之后,对完整网络进行微调以执行实际的分割。BT-Unet由IndianInstitute......
  • 分布式拒绝服务攻击(DDoS)和僵尸网络(Botnet)
    前言DDos和僵尸网络是相辅相成的两种攻击手段,本文仅介绍基本概念,详细请查看文末参考资料。分布式拒绝服务攻击(DDoS)分布式拒绝服务攻击DDoS是一种基于DoS的特殊形式的......
  • .NET 7介绍及
             环境要求 ......
  • ASP.NET获取远程网页下载到本地文件
    通过ASP.NET生成静态文件的文章网上有好多文章,而本站也有不少的相关文章教程,通常ASP.NET生成静态文件的做法是使用文件流读取模板内容,之后替换模板内容中相关关键字,再生成静......