• asp.net中的报销多级审批工作流


           最近正在学习工作流,正好从网上搜索到一个Asp.net工作流(WWF+LINQ)的例子,之前学习MOSS时接触过工作流,不过那是针对MOSS的工作流,我一直从事B/S架构开发,知道工作流可用于很多环境,其中就包含asp.net,这让我非常想做一个这样的实例。看了它的源码,大部分都觉的非常不错,不过也有些个人认为不太满意的地方,这可能是因为作者考虑到只是一个简单的demo,没有必要注意一些非技术方面的细节问题。

           项目介绍:一个报销二级审批工作流,数据层操作采用LINQ TO SQL,虽然MS不再发展示它。

              第一级:员工提交报销表给PM(经理),如果数目大于1000RMB,经理如果选择通过审批,工作流会到副总的二级审批,同时经理可以直接选择拒绝。

              第二级:PV(副总),副总收到PM的审批后,可以选择通过或者是拒绝,如果通过,工作流会提交到财务。由财务最后结束工作流。

           流程图如下:

     

           我创建的工作流与原作者的源码有以下几点不同:

               1:原文的工作流采用的是状态机工作流,而这里我采用顺序工作流。 

               2:把数据操作部分和业务逻辑以及页面层功能完全分开,即,只要是和数据访问,操作相关的代码只允许出现在数据处理层中,而业务逻辑层以及页面层均不允许,页面层只和业务逻辑层沟通,不允许直接访问数据处理层。

               3:工程的命名上有改动,例如:

                    解决方案名称:ApproveWorkFlow, 页面层叫ApproveWorkFlow.Web。

               4:对相关的方法做了适当的改进。

               5:增加方法以及文档注释。

           项目结构图如下:

     

           项目结构说明:

               1:ApproveWorkFlow.BLL:业务逻辑层。

               2:ApproveWorkFlow.Common,可以放些常用的方法,就是常说的工具类。

               3:ApproveWorkFlow.DAL,数据处理层,数据的增删改查。

               4:ApproveWorkFlow.Data,数据库的连接类,这里我放了一个dbml文件。

               5:ApproveWorkFlow.Model,实体类。

               6:ApproveWorkFlow.MyInterface,接口层。

               7:ApproveWorkFlow.MyWorkFlow,工作流。

               8: ApproveWorkFlow.Web,页面层。

            WF中的持久化服务:

                SqlWorkflowPersistenceService是WF框架中的一个SQL持久性服务(支持SQL Server2005)。在安装DotNet时并不会自动安装此类所需要的数据库。要正确使用此类必需执行以下步骤:

                1:打开Sql Server Management Stuio。

                2:新建一个数据库SqlPersistenceService,这个名字可以更改。

                3:执行相关数据库脚本:

                    1:%WINDOWS%"Microsoft.NET"Framework"v3.0"Windows WorkflowFoundation"SQL"EN"SqlPersistenceService_Schema.sql。

                    2:%WINDOWS%"Microsoft.NET"Framework"v3.0"Windows Workflow Foundation"SQL"EN"SqlPersistenceService_Logic.sql。

            创建报销审批工作流:

                1:在设计面板中拉一个WhileActivity;

                2:在代码中加入一个属性,标记while的执行条件:!this.IsCompleted

            /// <summary>
            
    /// 工作流的while条件
            
    /// </summary>
            private Boolean isCompleted = false;
            
    public Boolean IsCompleted
            {
                
    get { return isCompleted; }
                
    set { isCompleted = value; }
            }

              3:拉一个SequenceActivity。

              4:再放一个ListenActivity,也叫单线触发容器,使用EventDrivenActivity作为分支容器,当某条分支中的结点执行完成后,该ListenActivity结点就结束,继续向下执行,其他分支内的结点就不执行了,它不能应用于状态机工作流。

              5:加入所有的EventDrivenActivity。

              6:创建一个供EventDrivenActivity用的接口IApprove
     
    /// <summary>
        
    /// 这个接口标示为"ExternalDataExchange",目的是供工作流调用
        
    /// </summary>
        [ExternalDataExchange]
       
    public  interface IApprove
        {
            
    /// <summary>
            
    /// 员工提交报销记录事件
            
    /// </summary>
            event EventHandler<ExpenseAccountInfo> OnStaffSubmit;
            
    /// <summary>
            
    /// 员工删除报销记录事件
            
    /// </summary>
            event EventHandler<ExpenseAccountInfo> OnStaffDelete;
            
    /// <summary>
            
    /// 小额数据PM审批通过事件
            
    /// </summary>
            event EventHandler<ExpenseAccountInfo> OnPMSubmitMin;
            
    /// <summary>
            
    /// 大额数据PM审批通过事件
            
    /// 同时提交给副总审批
            
    /// </summary>
            event EventHandler<ExpenseAccountInfo> OnPMSubmitMax;
            
    /// <summary>
            
    /// PM拒绝审批事件
            
    /// </summary>
            event EventHandler<ExpenseAccountInfo> OnPMReject;
            
    /// <summary>
            
    /// 副总审批通过事件
            
    /// </summary>
            event EventHandler<ExpenseAccountInfo> OnVPSubmit;
            
    /// <summary>
            
    /// 副总拒绝审批事件
            
    /// </summary>
            event EventHandler<ExpenseAccountInfo> OnVPReject;
            
    /// <summary>
            
    /// 财务通过审批事件
            
    /// </summary>
            event EventHandler<ExpenseAccountInfo> OnFinanceSubmit;
        }

              7:设置EventDrivenActivity的属性:EventName,InterfaceType,Name,Invoked。InterfaceType选择第六步创建的接口。所有的工作流事件代码如下:

                 注意: 财务审批事件(OnFinanceSubmit_Invoked)是工作流最后一步,所以工作流的完成标志也要在这完成。

    private void OnStaffSubmit_Invoked(object sender, ExternalDataEventArgs e)
            {
                BllExpense Bll 
    = new BllExpense();
                info 
    = e as ExpenseAccountInfo;
                info.AppStatus 
    = "等待PM审批";
                Bll.AddRecord(info);
            }
            
    private void OnStaffDelete_Invoked(object sender, ExternalDataEventArgs e)
            {
                BllExpense Bll 
    = new BllExpense();
                info.AppStatus 
    = "结束";
                Bll.UpDateRecord(info);
            }
            
    private void OnPMSubmitMin_Invoked(object sender, ExternalDataEventArgs e)
            {
                BllExpense Bll 
    = new BllExpense();
                info.AppStatus 
    = "审批通过";
                Bll.UpDateRecord(info);
            }
            
    private void OnPMSubmitMax_Invoked(object sender, ExternalDataEventArgs e)
            {
                BllExpense Bll 
    = new BllExpense();
                info.AppStatus 
    = "等待VP审批";
                Bll.UpDateRecord(info);
            }
            
    private void OnPMReject_Invoked(object sender, ExternalDataEventArgs e)
            {
                BllExpense Bll 
    = new BllExpense();
                info.AppStatus 
    = "PM拒绝审批";
                Bll.UpDateRecord(info);
            }
            
    private void OnVPSubmit_Invoked(object sender, ExternalDataEventArgs e)
            {
                BllExpense Bll 
    = new BllExpense();
                info.AppStatus 
    = "审批通过";
                Bll.UpDateRecord(info);
            }
            
    private void OnVPReject_Invoked(object sender, ExternalDataEventArgs e)
            {
                BllExpense Bll 
    = new BllExpense();
                info.AppStatus 
    = "VP拒绝审批";
                Bll.UpDateRecord(info);
            }
            
    private void OnFinanceSubmit_Invoked(object sender, ExternalDataEventArgs e)
            {
                BllExpense Bll 
    = new BllExpense();
                info.AppStatus 
    = "结束";
                Bll.UpDateRecord(info);
                
    //结束工作流
                this.IsCompleted = true;
            }

              

             8:创建一个业务逻辑类BLL_Approve来实现IApprove。

    public  class BLL_Approve:IApprove
        {
           
    public event EventHandler<ExpenseAccountInfo> OnStaffSubmit;
            
    public event EventHandler<ExpenseAccountInfo> OnStaffDelete;
            
    public event EventHandler<ExpenseAccountInfo> OnPMSubmitMin;
            
    public event EventHandler<ExpenseAccountInfo> OnPMSubmitMax;
            
    public event EventHandler<ExpenseAccountInfo> OnPMReject;
            
    public event EventHandler<ExpenseAccountInfo> OnVPSubmit;
            
    public event EventHandler<ExpenseAccountInfo> OnVPReject;
            
    public event EventHandler<ExpenseAccountInfo> OnFinanceSubmit;     
            
    public void RaiseStaffSubmit(ExpenseAccountInfo info)
            {
                
    if (OnStaffSubmit != null)
                {
                    OnStaffSubmit(
    null, info);
                }
            }
            
    public void RaiseStaffDelete(ExpenseAccountInfo info)
            {
                
    if (OnStaffDelete != null)
                {
                    OnStaffDelete(
    null, info);
                }
            }
            
    public void RaisePMSubmitMin(ExpenseAccountInfo info)
            {
                
    if (OnPMSubmitMin != null)
                {
                    OnPMSubmitMin(
    null, info);
                }
            }
            
    public void RaisePMSubmitMax(ExpenseAccountInfo info)
            {
                
    if (OnPMSubmitMax != null)
                {
                    OnPMSubmitMax(
    null, info);
                }
            }
            
    public void RaisePMReject(ExpenseAccountInfo info)
            {
                
    if (OnPMReject != null)
                {
                    OnPMReject(
    null, info);
                }
            }
            
    public void RaiseVPSubmit(ExpenseAccountInfo info)
            {
                
    if (OnVPSubmit != null)
                {
                    OnVPSubmit(
    null, info);
                }
            }
            
    public void RaiseVPReject(ExpenseAccountInfo info)
            {
                
    if (OnVPReject != null)
                {
                    OnVPReject(
    null, info);
                }
            }
            
    public void RaiseFinanceSubmit(ExpenseAccountInfo info)
            {
                
    if (OnFinanceSubmit != null)
                {
                    OnFinanceSubmit(
    null, info);
                }
            }
        }

                9:把工作流加入到asp.net中:具体方法见代码,相关方法应用可参考MSDN。
           
    BllExpense Bll;
            
    static WorkflowRuntime runtime;//运行时
            static WorkflowInstance instance;//实例
            static ExternalDataExchangeService service;//外部数据交换服务
            static WorkflowPersistenceService perService;//持久化服务
            static BLL_Approve project;//实现接口类
            protected void Page_Load(object sender, EventArgs e)
            {
                Bll 
    = new BllExpense();
                
    if (!IsPostBack)
                {
                    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();
                }
            }
    public void OnWorkflowIdled(object sender, WorkflowEventArgs e)
            {
                e.WorkflowInstance.TryUnload();
    //将内存数据持久化到数据库中
            }

             10:用户提交数据启动工作流。


                
    //创建一个工作流实例
                instance = runtime.CreateWorkflow(typeof(ApproveWorkFlow.MyWorkFlow  .Workflow1 ));
                
    //启动工作流
                instance.Start();

                ExpenseAccountInfo info = new ExpenseAccountInfo(instance.InstanceId, 

    Convert.ToDecimal(this.tbMoney.Text), this.tbName.Text, 

    DateTime.Now.ToShortDateString(), "等待PM审批"this.tbNotes.Text);

                //触发工作流相应事件
                project.RaiseStaffSubmit(info);

              11:审批者审批工作流。

        Guid workflowId = new Guid(this.tbNo.Text);
                
    //根据报销单号取得一个未完成的工作流实例
                runtime.GetWorkflow(workflowId);

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

    DateTime.Now.ToShortDateString(), ""this.tbNotes.Text);

                if (info.Amount < 1000)
                {
                    info.AppStatus 
    = "审批通过";
                    
    //触发工作流事件
                    project.RaisePMSubmitMin(info);
                }
                
    else
                {
                    info.AppStatus 
    = "等待VP审批";
                    
    //触发工作流事件
                    project.RaisePMSubmitMax(info);
                }

           总结:本文并非原创,是以别人代码为基础,做了些改动,让它更接近一个真实的项目。

    原项目地址:http://download.csdn.net/down/948601/oxch2008

    本文参考:1:http://www.cnblogs.com/foundation/articles/529793.html
                 2:http://www.cnblogs.com/carysun/archive/2008/06/25/Persistence.html
  • 相关阅读:
    04_移动端-伪元素选择器
    03_移动端-结构伪类选择器
    02_移动端-属性选择器
    Dva+Antd创建React项目(一)
    Windows 10 使用打印机扫描
    中间件-redis
    #期望dp#51nod 2015 诺德街
    Codeforces Round #685 (Div. 2)
    USACO 4.2
    #保序回归问题,单调栈,二分#洛谷 5294 [HNOI2019]序列
  • 原文地址:https://www.cnblogs.com/ASPNET2008/p/1398072.html
Copyright © 2020-2023  润新知