WF

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

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

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

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

       流程图如下:

 WF

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

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

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

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

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

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

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

       项目结构图如下:

WF 

       项目结构说明:

           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

你可能感兴趣的:(WF)