(轉)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);
            }


       總結:本文並非原創,是以別人代碼爲基礎,做了些改動,讓它更接近一個真實的項目。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章