最近正在学习工作流,正好从网上搜索到一个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