首页 > 编程开发 > Objective-C编程 >
-
WF应用场景指南展现流Presentation Flow
原文地址:http://msdn.microsoft.com/en-us/library/dd557867.aspx
Windows Workflow Foundation (WF 或者 Workflow) 是微软推出的构建基于工作流应用程序的技术平台。这个平台包括一系列设计,管理工作流的工具,一个工作流编程模型,一个规则引擎和一个工作流的运行引擎。WF可以应用在很多的场景下---以下列表列出了一些最常用的场景:
应用场景
|
说明
|
SharePoint 2007 和WF协作
|
SharePoint 2007 使用WF作为默认的工作流技术,而且包括使用SharePoint Designer 2007 和 Visual Studio 2008创建的自定义工作流。
|
基于人的 Workflow
|
WF提供基于人的工作流和基于系统业务逻辑的工作流。
|
Workflow 服务
|
WF和WCF的无缝结合使得WF可以以WCF服务的方式暴露出来,并且可以调用WCF服务。
|
展现流
|
无论Windows程序还是Web程序,都可以使用WF驱动展现层的流程。
|
承载WF设计器
|
应用程序可以内嵌WF的工作流设计器,从而为最终用户提供全面的定制化服务。
|
表 1: 应用WF的常用场景
这篇白皮书概括了WF在展现流场景下的建议用法。
WF驱动展现流
MVC (Model View Controller) 是一个非常流行的将展现层,展现流和业务逻辑分离的模式。这个模式强迫开发人员将展现层与程序内部逻辑解耦---使得展现流更容易调整和重用。在MVC模式中,状态机工作流是Controller的理想选择。
当用户界面的导航逻辑十分复杂,更改十分频繁,或者使用向导模式时,WF的设计器非常适合展现流的设计,修改。因为WF可以被承载在任何的托管环境中,所以WF可以使用在Windows Forms 和 WPF 应用程序,ASP.NET 应用程序中。使用WF控制展现流的好处有以下几点:
使用工作流驱动用户界面,使得展现层和业务逻辑,UI导航逻辑解耦
通过清晰定义当前UI的状态和可以接受的操作,使得复杂的UI逻辑更明确和容易验证
通过修改工作流模型而不是修改松散的代码而更加简化展现流的修改
展现流进行架构设计
此展现流架构依赖于一个前提---WF Runtime 可以在任何的托管进程中运行,并且包括展现层和它所支持的中间层。 一个WF实例负责当前用户能见到哪个界面。当用户在UI上通过出发按钮事件导航时,事件被传递到WF的实例中。WF通过跳转到下一个状态,来向用户显示新的UI。图表 1 展示了WF用作展现流的通用架构。
图片看不清楚?请点击这里查看原图(大图)。
图表 1: 展现流架构
展现流可以应用于Windows Forms, WPF和ASP.NET应用中。 实际上,应用展现流的唯一条件就是UI进程中可以运行WF Runtime。 展现流架构的核心是状态机工作流---工作流的每一个状态都和UI的一个界面一一对应,例如一个WPF窗体或ASP.NET页面。当用户对UI进行操作时,后台工作流实例状态的改变,直接使得UI显示下一个界面。
状态机工作流除了工作原理上与展现流相符合之外,还有三个特性可以更好地控制展现流。第一,状态机工作流可以随时转向任意一个状态,这使得UI可以脱离只能顺序执行的束缚。例如可以在开始时根据某个条件退出程序,回退到之前的某个步骤等等。第二,状态机可以动态地构建当前状态下可以出现的UI界面。最后,由于状态可以嵌套,使得一个针对于某个状态的事件可以在多个位置处理。这意味着全局事件,可以利用它在任何时候取消流程。
WF可以以多种形式控制UI流程。当状态机改变状态时,通过松耦合的方式通知UI更新界面。在这种情况下,WF的Local Service承担UI层和WF的沟通和解耦的工作。WF实例通过Local Service接收到UI的事件,改变自己的状态,再通过Local Service 通知UI更改界面。
交互过程见图表 2.
图片看不清楚?请点击这里查看原图(大图)。
图表 2: 通过工作流控制UI的松耦合架构
此外,WF也可以自己负责更新UI。图表 3 列出了架构。
图片看不清楚?请点击这里查看原图(大图)。
图表 3: 工作流负责更新UI
在上述两种情况中,WF持久化服务扮演了重要角色---它允许用户暂时终止应用程序,并且在将来的某个时间在原来终止的位置重新恢复执行。接下来的两个章节,将以Windows Forms和ASP.NET应用程序分别介绍以上两种架构的实现。
ASP.NET 展现流
通常一个网站或一个企业级的网络应用包含很多的页面---其中一些页面会需要类似于向导风格的展现流。然而有时,需要重用某个页面,或者对向导的顺序进行调整。对于导航代码散落在各个页面的情况,管理这些逻辑是非常麻烦的,尤其是要重用的页面是处在不同的上下文,这会带来很大的维护开销和隐患。从每一个页面中提取,抽象,导航逻辑,并使之可视化(WF设计器)可使得网站更灵活,并易于管理。
图表 4 列出了一个包含一系列页面的,基于ASP.NET的允许用户订阅简讯的例子。 第一个页面允许用户选择所感兴趣的项目,第二页允许用户选择简讯递送的格式,最后一页让用户输入姓名和Email地址。
图片看不清楚?请点击这里查看原图(大图)。
图表 4: ASP.NET 收集简讯订阅向导
下一个章节将会描述使用WF控制展现流的具体实现。
实现架构
图表 5 列出了一个针对图表4中向导的状态机工作流。每一个页面用一个状态代表。每一个状态都定义了当前状态可以执行的操作,包括向前,向后,结束。
图片看不清楚?请点击这里查看原图(大图)。
图表 5: 针对图表4的状态机工作流
下面是工作流的逻辑:
当工作流初始化时,状态是Page1,当工作流处于初始状态时,应用程序导航至Page1。
在Page1中,用户点击Next按钮,会触发工作流的一个事件,使得工作流转向Page2状态。
应用程序察觉工作流状态改变,根据最新状态导航至Page2。
在Page2中,用户可以选择向前和向后,这回导致工作流状态改变,并最终导致应用程序导航至相应的页面。
在Page3中,如果用户点击Finish按钮,工作流会结束,从而应用程序也就结束了。
页面的导航逻辑可以包含在WF的代码中,或者应用程序察知工作流状态改变,自行导航。两种方法都没有对页面导航逻辑硬编码---而是根据工作流状态的更改,确定导航的逻辑。为了能达到这个目的,WF必须运行在页面请求所在的线程中,而且不能异步执行(WF默认是异步执行的)。可以通过WF的Manual Scheduler Service达到这一目的。
图表 6 列出了这一架构
图片看不清楚?请点击这里查看原图(大图)。
图表 6: ASP.NET 展现流架构
为了节省每个页面请求的时间,WF Runtime被存储在 ASP.NET 缓存中。当用户访问第一关页面时,工作流实例被创建,并把实例存储在Session中,以备后用。当用户和页面交互时,WF Runtime被应用程序从缓存中获得,运行存储在Session中的WF实例。
持久化服务被启用,保证WF实例可以在用户意外离开,甚至在另一个时间和位置登录时(另一个WEB服务器),可以重新运行工作流。
页面中的事件处理器,依靠WF的Local Service 触发工作流的相应事件。因为是手动调度WF的执行(同步模式),所以页面会等待WF的状态改变。如果工作流没有页面导航逻辑的话,应用程序可以根据WF的状态导航到相应的页面。
Windows Client 展现流
Windows 应用程序拥有更多的UI,同样也可以使用WF解耦向导型的程序。基于向导的Windows应用程序包含更复杂的业务逻辑,这些逻辑可以完全整合到WF中。事实上,使用状态机工作流的一个很大的好处是,你可以在清晰地看到顶层的导航逻辑,并且可以钻取到每一个状态中,查看更详细,复杂的逻辑。
图表7 列出了一个由WPF构建的基于向导的安装程序的成功路径。每一个窗口收集用户信息并显示当前状态的信息。
图片看不清楚?请点击这里查看原图(大图)。
图表 7: 基于WPF的向导型安装程序
下面的章节将讲述其实现架构。在这里会用到状态机和顺序两种工作流。
实现架构
这个安装程序基于WPF,并承载WF的Runtime。程序本身并不直接运行安装操作,取而代之的是,创建一个WF的实例,并等待它执行结束。工作流负责显示每个窗体,并在窗体显示之前,之后执行安装逻辑。然后等待用户输入必要信息后,转向下一状态。当工作流执行完全部逻辑之后,就无需与宿主应用程序通过Local Service交互了。
图表 8 列出了状态机工作流的顶层视图,描述了安装程序的流程。
图片看不清楚?请点击这里查看原图(大图)。
图表 8: Activity 执行时显示对应的 Windows Forms
每一个状态内部包含一个顺序工作流,定义当前状态下的安装逻辑。你可以向下,向下钻取,查看两种工作流如何合作.
图片看不清楚?请点击这里查看原图(大图)。
图表 9: ExecInstall 状态中的顺序工作流
在此示例中使用WF的其中一个好处是,可以定义安装程序如何处理安装过程的错误。在此示例中,如何安装程序被取消,所以拷贝的文件都必须被删除,并返回到安装程序运行之前的状态。WF可以包含补偿逻辑。上例中(图表 9),InstallOrRollback是一个CompensatableSequenceActivity类的Activity,即有补偿逻辑的活动。通过补偿逻辑,可以在异常发生时,进行必要的处理。图表 10 和图表 11列出了InstallOrRollback Activity的补偿视图。当异常发生时,补偿逻辑被执行---删除所有拷贝的文件。
图表 10: 选择CompensatableSequenceActivity 的补偿视图
图表 11: CompensationHandlerActivity 的补偿逻辑
常见问题
问. 可否定义同一个工作流分别驱动ASP.NET 和 Windows 应用程序?
可以。通过定义一个工作流,可以分别驱动ASP.NET和Windows 应用程序的展现流。这两种模式的不同主要是宿主运行WF的线程模型。在ASP.NET 的场景中,必须使用ManualWorkflowSchedulerService 服务使WF实例与页面运行在同一线程中。否则WF会以异步的方式运行(与宿主不在同一线程),这样WF就不能导航页面了。
在 Windows 应用程序场景下,可以使用任意种调度模型。如果使用DefaultWorkflowSchedulerService 服务(默认的异步模型),因为WF实例与UI不运行在同一线程中,所以需要额外的代码来交互---尤其是根据状态更改UI时。如果使用ManualWorkflowSchedulerService 服务(同步模式),WF实例与UI运行在同一线程。此时WF可以直接更新UI,无需额外的线程间交互代码。
问. 在WF控制展现流的Windows 应用程序中,通过WF显示模式窗体,是一个好主意吗?
在WF中显示模式窗体意味着:当模式窗体关闭时,自动显示另一个窗体。这会导致两个窗体交替时出现不必要的闪烁---但这样的方式在有些情况下是可以接受的,例如安装程序。一般商业应用程序需要窗体之间的平滑过渡,所以WF线程和UI线程之间的通信是值得的。WF触发的事件可以传递数据到宿主程序中,宿主程序可以根据WF的状态更新UI。问. 在 ASP.NET 应用中使用WF对性能有何影响?
当WF运行在一个长生命周期的应用中时,加载WF实例的开销是无需担心的。当WF以在同步模式执行时,开销会大一些。当网站UI导航非常复杂时,则要权衡导航逻辑的复杂性和WF所带来的开销。在 .NET 4.0中,WF Runtime 的效率提升会使得此方案更可行。
问. 为什么使用WF实现而不是使用 ASP.NET MVC?
MVC是一个非常好的页面流技术,但并未提供向WF那样的可视化设计器,因此更复杂的UI还是WF比较合适。
问. 当用户回退时,如何保持页面和WF之间的同步?
每一个页面都可以通过视View State保存WF的实例标识和当前WF的状态。这样,当用户回退时,View State可以帮助重新加载正确的WF实例,并且或者设置WF的状态为页面保存的状态,或者提示用户错误---如果应用程序要求的话。