本文中介绍一个在ASP.NET 3.5 Web应用中使用WWF的
基本
实例。因为VS2008没有提供现成的支持
ASP.NET 3.5 Web应用的模板,所以相对于基本的控制台工作流实例,实施起来略微复杂一点。因此,阅读下文时请注意与控制台
工作流
应用的区别。
因为我们想在本例中实现根据用户输入人民币数额的不同而把用户导航到不同的页面。所以,我们在默认页面 default.aspx 中添加一些简单的内容,如下图所示(注意其中使用了母版页面):
接下来,再依次添加两个普通页面,一个是显示银行存款信息的页面 credit.aspx,另一个是显示 借款信息的页面 debit.aspx 。当用户输入金额小于100时,用户被导航到 页面 debit.aspx;否则,被 导航到 页面 credit.aspx 。
接下来,打开 文件 Global.asax,并添加如下所示的工作流代码。
通过上述代码,我们可以确保
工作流运行时
实例
的唯一性。请参考后文理解这里的代码。
选择上图中 ifElseActivity活动 的左分支,通过“属性”对话框设定其触发条件为”代码条件“,随后输入其条件函数名为ValidateAmount。 按下回车键,切换到后台代码文件中,输入如下代码:
注意到代码中出现一个Amount属性,有关它的定义方式请往下阅读。
在本例中,我们要创建两个工作流属性Amount和Result。使用类似思想创建这两个属性。最后得到如下所示的代码(基本是自动化生成的,仅需要修改一个属性名称及typeof后面的数据类型即可):
请注意上面两个属性的数据类型。
另外,这里定义的两个依赖性属性是典型的传递到工作流实例中的参数的方式。 而且, 在工作流宿主(本例中是ASP.NET网站程序)和 工作流 间传递参数的 最容易的方法 方式是使用字典集合,这些将在后面使用到。
然后,在代码隐藏文件中创建具体负责初始化并启动工作流的私有方法InitiateWorkFlow,如下所示:
上述代码实现了如下功能:
现在,我们简单讨论一下ManualWorkflowSchedulerService。在上一节中,在 Application_Start 事件期间创建了 WorkflowRuntime 实例。 在 Web 应用程序处理请求时,会一直保留此对象。上面的代码展示如何从 ASP.NET 中的 Application 对象中检索 WorkflowRuntime 实例。 之后,使用 GetService 方法检索用于启动工作流的 ManualWorkflowSchedulerService,以便同步运行工作流。 为此,调用在 WorkflowRuntime 类中定义的 CreateWorkflow 方法,随后调用从 CreateWorkflow 调用中返回的 WorkflowInstance 对象中的 Start 方法。 由于将 ManualWorkflowSchedulerService 添加到了 WorkflowRuntime,因此调用 RunWorkflow 方法,传递WorkflowInstance 对象的 InstanceId。
接下来,我们看地下事件WorkFlowCompleted的实现代码:
在此事件方法中,请注意事件参数eventArgument 成为WorkflowCompletedEventArgs类型。此参数有一个集合称作Outputparametes,其中包含了工作流参数集合。因此,我们可以检索工作流参数” Result“ 的值,以用于我们设计中的页面的重定向。
现在,输入数字200后按下”提交“按钮,你会被导航到如下页面:
按下浏览器的后退按钮再回到默认页面,再输入数字50,
按下”提交“按钮,你会被导航到如下页面:
http://space.itpub.net/14466241/viewspace-615442
一、创建ASP.NET 3.5网站
启动VS2008,单击菜单”文件“|”新建“|”网站“,创建一个名字为IntroASPNET35WWF 的ASP.NET 3.5网站。因为我们想在本例中实现根据用户输入人民币数额的不同而把用户导航到不同的页面。所以,我们在默认页面 default.aspx 中添加一些简单的内容,如下图所示(注意其中使用了母版页面):
接下来,再依次添加两个普通页面,一个是显示银行存款信息的页面 credit.aspx,另一个是显示 借款信息的页面 debit.aspx 。当用户输入金额小于100时,用户被导航到 页面 debit.aspx;否则,被 导航到 页面 credit.aspx 。
二、在示例网站中添加工作流相关程序集的引用
右单击示例网站,选择“添加引用”。在 “添加引用”对话框中切换到”.NET“选项卡,选择如图所示的工作流相关程序集。最后,单击”确定“按钮 (请注意,这几个程序集的版本是不同的) 。三、添加全局应用程序类文件Global.asax
因为我们想控制工作流运行时的唯一实例,所以在示例中添加一个 全局应用程序类文件Global.asax 。右单击示例网站,选择“添加新项”。在 “添加新项”对话框中选择” 全局应用程序类 “模板添加文件 Global.asax,如图所示 。接下来,打开 文件 Global.asax,并添加如下所示的工作流代码。
void Application_Start(object sender, EventArgs e) { System.Workflow.Runtime.WorkflowRuntime workflowRuntime = new System.Workflow.Runtime.WorkflowRuntime(); System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService manualService = new System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService(); workflowRuntime.AddService(manualService); workflowRuntime.StartRuntime(); Application["WorkflowRuntime"] = workflowRuntime; } void Application_End(object sender, EventArgs e) { System.Workflow.Runtime.WorkflowRuntime workflowRuntime = Application["WorkflowRuntime"] as System.Workflow.Runtime.WorkflowRuntime; workflowRuntime.StopRuntime(); } |
四、添加顺序工作流库
单击菜单”文件“|”添加“|”新建项目“,添加一个命名为WorkflowLibrary1 的顺序工作流库,如图所示。五、设计工作流
上述步骤之后,系统自动打开工作流设计器界面。 根据前面的分析,我们把一个ifElseActivity类型的活动拖动到工作流设计器中。然后,在左右两个分支中分别拖入两个代码活动,最后结果如下图所示。选择上图中 ifElseActivity活动 的左分支,通过“属性”对话框设定其触发条件为”代码条件“,随后输入其条件函数名为ValidateAmount。 按下回车键,切换到后台代码文件中,输入如下代码:
private void ValidateAmount(object sender, ConditionalEventArgs e) { if (this.Amount > 100) e.Result = true; } |
注意到代码中出现一个Amount属性,有关它的定义方式请往下阅读。
六、定义工作流属性
切换到工作流后台代码文件workflow1.cs, 右键单击代码空白处,选择“插入代码段”-“Other”-“Workflow”-“WorkflowDependency-Property”插入一个依赖性属性,如下图所示。此后,系统会把插入点自动停留在待重新确定名称的属性上。在本例中,我们要创建两个工作流属性Amount和Result。使用类似思想创建这两个属性。最后得到如下所示的代码(基本是自动化生成的,仅需要修改一个属性名称及typeof后面的数据类型即可):
public static DependencyProperty AmountProperty = DependencyProperty.Register("Amount", typeof(string), typeof(Workflow1)); [DescriptionAttribute("Amount")] [CategoryAttribute("Amount Category")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public string Amount { get { return ((string)(base.GetValue(Workflow1.AmountProperty))); } set { base.SetValue(Workflow1.AmountProperty, value); } } public static DependencyProperty ResultProperty = DependencyProperty.Register("Result", typeof(string), typeof(Workflow1)); [DescriptionAttribute("Result")] [CategoryAttribute("Result Category")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public string Result { get { return ((string)(base.GetValue(Workflow1.ResultProperty))); } set { base.SetValue(Workflow1.ResultProperty, value); } } |
请注意上面两个属性的数据类型。
另外,这里定义的两个依赖性属性是典型的传递到工作流实例中的参数的方式。 而且, 在工作流宿主(本例中是ASP.NET网站程序)和 工作流 间传递参数的 最容易的方法 方式是使用字典集合,这些将在后面使用到。
七、定义代码活动的ExecuteCode属性值
切换到工作流设计器界面,通过属性对话框依次把条件活动的左、右两个分支中的代码活动的ExecuteCode属性函数名修改为RedirectCredit和RedirectDebit。然后,双击这些函数并输入如下所示代码:private void RedirectCredit(object sender, EventArgs e) { this.Result = "Credit.aspx"; } private void RedirectDebit(object sender, EventArgs e) { this.Result = "Debit.aspx"; } |
八、启动工作流
双击示例网站中的页面Default.aspx中的按钮控件,并在按钮的Click事件处理器函数中输入如下代码:protected void Button1_Click(object sender, EventArgs e) { InitiateWorkFlow(); } |
然后,在代码隐藏文件中创建具体负责初始化并启动工作流的私有方法InitiateWorkFlow,如下所示:
private void InitiateWorkFlow() { Dictionary<string, object> parameters = new Dictionary<string, object>(); parameters.Add("Amount",Convert.ToInt32(TextBox1.Text)); parameters.Add("Result", ""); WorkflowRuntime wfRuntime = Application["WorkflowRuntime"] as System.Workflow.Runtime.WorkflowRuntime; wfRuntime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(wfRuntime_WorkflowCompleted); WorkflowInstance wi = wfRuntime.CreateWorkflow(typeof(WorkflowLibrary2.Workflow1), parameters); wi.Start(); ManualWorkflowSchedulerService ss = wfRuntime.GetService<ManualWorkflowSchedulerService>(); ss.RunWorkflow(wi.InstanceId); //HttpContext.Current.Session["WorkflowID"] = wi.InstanceId; } |
上述代码实现了如下功能:
- 根据前面的描述,我们定义的字典集合对象正是用作在工作流宿主和工作流间传递参数的方式。在此,我们把两个参数(Amount和Result)添加到该集合中。
- 然后声明了一个WorkflowRuntime对象,并把来自于网站中的工作流运行时对象(请参考前面的全局应用程序类中的application_Start事件代码)加载于其中。
- 然后添加上述工作流运行时的WorkflowCompleted事件处理器函数。
- 然后,创建工作流实例WorkFlowInstance(请注意参数是如何传递到方法CreateWorkflow中的)。
- 启动工作流实例。
现在,我们简单讨论一下ManualWorkflowSchedulerService。在上一节中,在 Application_Start 事件期间创建了 WorkflowRuntime 实例。 在 Web 应用程序处理请求时,会一直保留此对象。上面的代码展示如何从 ASP.NET 中的 Application 对象中检索 WorkflowRuntime 实例。 之后,使用 GetService 方法检索用于启动工作流的 ManualWorkflowSchedulerService,以便同步运行工作流。 为此,调用在 WorkflowRuntime 类中定义的 CreateWorkflow 方法,随后调用从 CreateWorkflow 调用中返回的 WorkflowInstance 对象中的 Start 方法。 由于将 ManualWorkflowSchedulerService 添加到了 WorkflowRuntime,因此调用 RunWorkflow 方法,传递WorkflowInstance 对象的 InstanceId。
接下来,我们看地下事件WorkFlowCompleted的实现代码:
static void wfRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e) { HttpContext.Current.Response.Redirect((string)e.OutputParameters["Result"]); } |
在此事件方法中,请注意事件参数eventArgument 成为WorkflowCompletedEventArgs类型。此参数有一个集合称作Outputparametes,其中包含了工作流参数集合。因此,我们可以检索工作流参数” Result“ 的值,以用于我们设计中的页面的重定向。
九、观察运行结果
按F5运行控制台程序,一般顺利的话,将得到如下图所示运行时快照。小结
上面给出的仅仅是一个入门级的例子,旨在探讨ASP.NET 3.5环境与WWF联合开发的基本原理。以后的文章中,我会继续给出 ASP.NET 3.5环境与WWF联合开发的更复杂更应用的案例。http://space.itpub.net/14466241/viewspace-615442