asp.net中的报销多级审批工作流 (状态机版本)
上篇asp.net中的报销多级审批工作流 ,提到参考了网上一个具体的项目,项目中用状态机工作流完成,基于学习的原因,我采用顺序工作流,事件驱动方式实现了同样的功能。后来学习到了状态机,觉的状态机实现也特别方便。 下面我分享下状态机工作流中几个主要的活动。
顺序工作流与状态机工作流的区别:
顺序工作流是一种可以预测,流程比较固定,而状态机工作流不可预测,主要靠外部事件驱动来实现,对外的交互比较多,系统的状态需要外部事件的触发来改变。
状态机工作流活动图:
1:State Activity,在状态机工作流中代表了一个具体的状态,这种状态机以事件驱动为主,和之前顺序工作流中的事件驱动有点类似。在整个状态机工作流中,会有一个初始化的State Activity和一个表示完成的State Activity,我们从工具箱中拉一个State Activity,然后单击右键,出现如下图,绿色的表示初始化State Activity,而红色的表示完成的State Activity,分别会在State Activity的左上角有相应的标示。
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