本文主要讲述,在web上实际应用上篇文章中设计的工作流。。。。
涉及技术
在Web.config 配置
取得工作流结构
动态加签
动态取得审批方式
启动工作流流转等(这个好多列子中都有不再详细描述)
Web 项目文件主要功能描述
说明
- Web.Config
配置了一些工作流服务
WorkflowRuntime 加载的,ManualWorkflowSchedulerService 和 ExternalDataExchangeService
ExternalDataExchangeService 加载的,上篇文章中的 MyWorkflows.BillServer- Global.asax,App_Code\Global.asax.cs
启动 WorkflowRuntime,加载 FileWorkflowPersistenceService(自定义的状态保存服务,下篇文章详细讲解)
代码
protected void Application_Start( object sender, EventArgs e)
{
Console.WriteLine( " Application_Start: " );
System.Workflow.Runtime.WorkflowRuntime workflowRuntime = new System.Workflow.Runtime.WorkflowRuntime(MyWorkHelpr.WorkflowRuntimeName);
// 加载状态保持服务(自己的类),构造函数设置保存状态的路径
FileWorkflowPersistenceService f28s = new FileWorkflowPersistenceService(Server.MapPath( " ~/App_Data/XOM.WFDB/ " ));
workflowRuntime.AddService(f28s);
Application[MyWorkHelpr.WorkflowRuntimeName] = workflowRuntime;
// 映射事件没用上
workflowRuntime.WorkflowCompleted += new EventHandler < System.Workflow.Runtime.WorkflowCompletedEventArgs > (workflowRuntime_WorkflowCompleted);
workflowRuntime.WorkflowTerminated += new EventHandler < System.Workflow.Runtime.WorkflowTerminatedEventArgs > (workflowRuntime_WorkflowTerminated);
workflowRuntime.WorkflowSuspended += new EventHandler < System.Workflow.Runtime.WorkflowSuspendedEventArgs > (workflowRuntime_WorkflowSuspended);
workflowRuntime.WorkflowPersisted += new EventHandler < System.Workflow.Runtime.WorkflowEventArgs > (workflowRuntime_WorkflowPersisted);
workflowRuntime.StartRuntime();
// 重状态保存读取所有没执行完的了类.
foreach (Guid id in f28s.GetAllWorkflows())
{
workflowRuntime.GetWorkflow(id);
}
}- Default.aspx (用户登陆)
导航页面,可以模拟各种角色登陆,可以显示全部正在进行的工作流信息、可以查看工作流的结构
代码说明
取得工作流结构
protected void GridView1_RowCommand( object sender, GridViewCommandEventArgs e)
{
int i = 0 ;
if (e.CommandName.ToLower() == " select " )
{ // 就想取两级就不递归了
i = Convert.ToInt32(e.CommandArgument);
string sguid = GridView1.Rows[i].Cells[ 1 ].Text.Trim();
Guid instanceId = new Guid(sguid);
WorkflowInstance workInstance = (Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetWorkflow(instanceId);
StateMachineWorkflowActivity MainActivity = workInstance.GetWorkflowDefinition() as StateMachineWorkflowActivity;
TreeView1.Nodes.Clear();
TreeNode MainNode = new TreeNode();
TreeNode NodeL1 = null ;
TreeNode NodeL2 = null ;
MainNode.Text = sguid;
foreach (StateActivity state in MainActivity.Activities)
{
NodeL1 = new TreeNode();
NodeL1.NavigateUrl = " # " ;
NodeL1.Text = state.Name + " : " + state.Description;
foreach (CompositeActivity cactive in state.Activities)
{
NodeL2 = new TreeNode();
NodeL2.NavigateUrl = " # " ;
NodeL2.Text = cactive.Name + " : " + cactive.Description;
NodeL1.ChildNodes.Add(NodeL2);
}
MainNode.ChildNodes.Add(NodeL1);
}
MainNode.ExpandAll();
TreeView1.Nodes.Add(MainNode);
// btnReadGuid_Click(btnReadGuid, null);
}
}- CreateBill.aspx (创建修改报销单)
填写表单,根据金额判断跳转到老板,还是财务(跳转是在ASP.net程序中控制的,其实也可以在工作流里控制,有情趣的可以自己改改)
代码
protected void btnOk_Click( object sender, EventArgs e)
{
if (TextBox1.Text.Length > 0 )
{
Guid InstanceId = new Guid(TextBox1.Text);
BillServer billserver = (Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetService < BillServer > ();
ManualWorkflowSchedulerService scheduler = (Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetService < ManualWorkflowSchedulerService > ();
decimal money = decimal .Parse(txt3.Text);
if (money < 1 ) return ;
string wsPath = HttpContext.Current.Server.MapPath( " ~/App_Data/WorkflowSave/ " );
// 如果已经有数据取得
BillModel model = FileTools.XmlDeserializeObject(wsPath
, InstanceId
, typeof (BillModel)) as BillModel;
if (model == null ) model = new BillModel();
model.BillId = txt1.Text;
model.Money = money;
model.UserName = txt2.Text;
if (model.Money > 1000 )
{ // 流转到老板
billserver.RaiseEvent( " BillInitMoneyMax " , InstanceId);
}
else
{ // 流转到财务
billserver.RaiseEvent( " BillInitMoneyMin " ,InstanceId);
}
// 流转工作流
scheduler.RunWorkflow(InstanceId);
TextBox1.Text = "" ;
// 保存更改的数据
FileTools.XmlSerializeObject(wsPath
, InstanceId
, model);
// this.Response.Redirect("default.aspx", false);
}
}- Finance.aspx (财务)
页面加载显示财务应该处理的流程,选择一个正在进行的流程进行审批,动态取得审批方式到下拉框(审批方式是工作流设计器上设计的)、如果需要可以动态增加一个老板加签
代码说明
动态取得审批方式到下拉框的代码
protected void btnReadGuid_Click( object sender, EventArgs e)
{
string s = txtGuid.Text.Trim();
if (s.Length > 0 )
{
Guid instanceId = new Guid(s);
// 取得当前工作流里正在进行的 StateMachineWorkflow (这里是 stateFinance)
StateMachineWorkflowInstance stateInstance = new StateMachineWorkflowInstance(Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime, instanceId);
using (DataTable dt = new DataTable())
{
// 创建一个下拉框用的 DataTable
dt.Columns.Add( " NID " , typeof ( string )); // 保存 EventDrivenActivity 的名字,在确定时使用
dt.Columns.Add( " NTEXT " , typeof ( string )); // 保存 EventDrivenActivity 的说明
dt.Rows.Add( " -1 " , " ==请选择== " );
int i = 0 ;
foreach (Activity act in stateInstance.CurrentState.EnabledActivities)
{ // 循环当前流程可以用的 Activitie (在本步骤就是设计器里的 stateFinance 中的那些 EventDrivenActivity)
if (act is EventDrivenActivity )
{
EventDrivenActivity edact = (EventDrivenActivity)act;
if (edact.EnabledActivities.Count > 0 && edact.EnabledActivities[ 0 ] is HandleExternalEventActivity)
{ // 取得每个 EventDrivenActivity 中第一个 HandleExternalEventActivity 把名字和说明放到 dt 中
dt.Rows.Add(edact.Name, act.Description);
}
}
i ++ ;
}
// DataBind
DropDownList1.DataValueField = " NID " ;
DropDownList1.DataTextField = " NTEXT " ;
DropDownList1.DataSource = dt;
DropDownList1.DataBind();
}
}
}
动态加签的代码
protected void Button2_Click( object sender, EventArgs e)
{
string s = txtGuid.Text.Trim();
if (s.Length > 0 )
{
Guid instanceId = new Guid(s);
WorkflowInstance workInstance = (Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetWorkflow(instanceId);
// 取得整个工作流对象
StateMachineWorkflowActivity activity = (StateMachineWorkflowActivity)workInstance.GetWorkflowDefinition();
// 用 WorkflowChanges 榜定 activity
WorkflowChanges wfc = new WorkflowChanges(activity);
// 取得财务的 StateActivity
StateActivity state = (StateActivity)wfc.TransientWorkflow.Activities[ " stateFinance " ];
if (state.Activities[ " eveToBoss " ] != null ) return ;
// 声明一个外部事件
HandleExternalEventActivity externalEveTmp = new HandleExternalEventActivity();
externalEveTmp.EventName = " BillInsert " ;
externalEveTmp.InterfaceType = typeof (MyWorkflows.IBILLService);
externalEveTmp.Name = " externalEveTmp " ;
// 设置一个跳转
SetStateActivity setActTmp = new SetStateActivity();
setActTmp.Name = " setActTmp " ;
setActTmp.TargetStateName = " stateBoss " ;
EventDrivenActivity EventDrivenTmp = new EventDrivenActivity();
EventDrivenTmp.Activities.Add(externalEveTmp);
EventDrivenTmp.Activities.Add(setActTmp);
EventDrivenTmp.Description = " *老板加签* " ;
EventDrivenTmp.Name = " eveToBoss " ;
// 挂起
workInstance.Suspend( " 正在加签 " );
// 财务的 StateActivity 中加入一个 EventDrivenActivity
state.Activities.Add(EventDrivenTmp);
ValidationErrorCollection err = wfc.Validate();
// 应用更改
workInstance.ApplyWorkflowChanges(wfc);
// 恢复
workInstance.Resume();
btnReadGuid_Click(btnReadGuid, new EventArgs());
}
}
确定按扭时使用 下拉框 里的审批方式
protected void Button1_Click( object sender, EventArgs e)
{
string s = txtGuid.Text.Trim();
if (s.Length > 0 && DropDownList1.SelectedValue != " -1 " )
{
// 取得下拉框选择的 value btnReadGuid_Click 中取得的
string nid = DropDownList1.SelectedValue;
Guid instanceId = new Guid(s);
BillServer billserver = (Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetService < BillServer > ();
ManualWorkflowSchedulerService scheduler = (Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetService < ManualWorkflowSchedulerService > ();
StateMachineWorkflowInstance stateInstance = new StateMachineWorkflowInstance(Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime, instanceId);
// 通过名称取得 EventDrivenActivity
EventDrivenActivity edact = (EventDrivenActivity)stateInstance.CurrentState.Activities[nid];
// 和第一个 HandleExternalEventActivity
HandleExternalEventActivity heva = (HandleExternalEventActivity)edact.EnabledActivities[ 0 ];
// WorkflowInstance workInstance = stateInstance.WorkflowInstance;
// BillWorkflow act = stateInstance.WorkflowInstance.GetWorkflowDefinition() as BillWorkflow;
string wsPath = HttpContext.Current.Server.MapPath( " ~/App_Data/WorkflowSave/ " );
BillModel model = FileTools.XmlDeserializeObject(wsPath
, instanceId
, typeof (BillModel)) as BillModel;
model.LastRemark = model.Fremark = string .Concat( " 财务: " , DropDownList1.SelectedItem.Text, " : " , txtRemark.Text);
// 通过 HandleExternalEventActivity.EventName 调用 BillServer.RaiseEvent 触发外部事件使工作流向前运行
// 这就是我为上一章何在 BillServer 重写那些事件的原因
billserver.RaiseEvent(heva.EventName, instanceId);
// 工作流向下流转
scheduler.RunWorkflow(instanceId);
FileTools.XmlSerializeObject(wsPath,instanceId,model);
DropDownList1.Items.Clear();
txtGuid.Text = "" ;
// stateInstance.CurrentStateName
return ;
// // 如果用过一次要删除
// if(edact.Name == "eveToBoss") // 删除加签
// {
// // WorkflowInstance workInstance = (Application[MyWorkHelpr.WorkflowRuntimeName] as WorkflowRuntime).GetWorkflow(instanceId);
// workInstance.Suspend("正在删除加签");
// StateMachineWorkflowActivity activity = workInstance.GetWorkflowDefinition() as StateMachineWorkflowActivity;
// WorkflowChanges wfc = new WorkflowChanges(activity);
// // StateActivity sa = wfc.TransientWorkflow.Activities["stateFinance"] as StateActivity;
// StateActivity state = (StateActivity)wfc.TransientWorkflow.Activities["stateFinance"];
// state.Activities.Remove(state.Activities["eveToBoss"]);
// ValidationErrorCollection err = wfc.Validate();
// workInstance.ApplyWorkflowChanges(wfc);
// workInstance.Resume();
// // this.Response.Redirect("");
// }
}
}- Boss.aspx (老板)
页面加载显示老板应该处理的流程,选择一个正在进行的流程进行审批,动态取得审批方式到下拉框- PayBox.aspx (出纳)
页面加载显示出纳应该处理的流程,选择一个正在进行的流程进行审批,动态取得审批方式到下拉框- OutMoney.aspx(取钱确认)
页面加载子显示出纳审批Ok 的流程,选择一个正在进行的流程确认以读取,动态取得审批方式到下拉框其实重财务以后的页面处理方式都基本是一样的,界面也都类似,不再多说...