组件化和可扩展的工作流模型的制作方法

文档序号:6647142阅读:940来源:国知局

专利名称::组件化和可扩展的工作流模型的制作方法
技术领域
:本申请的实施例涉及工作流建模领域。更为具体地,本发明的实施例涉及组件化和可扩展工作流模型。
背景技术
:现有系统试图通过对商业问题建模而将商业问题映射到高级工作流。然而,真实世界地工作流在各方面都有所不同,这些方面诸如(a)执行和建模的复杂性、(b)设计时对工作流的结构的知识、(c)静态定义或特别/动态、(d)在其生命周期中各点创作和编辑该工作流的简易性、以及(e)与核心工作流过程的弱或强商业逻辑关联。现有模型无法容纳所有这些因素。此外,大多数现有工作流模型是以基于语言的方法(例如,BPEL4WS、XLANG/S和WSFL)或基于应用程序的方法为基础的。基于语言的方法是具有一闭合的预定义构造集的高级工作流语言,它帮助向用户/程序员建模该工作流过程。工作流语言载有供该闭合构造集使用的所有语义信息,以使用户能够构建工作流模型。然而,语言无法由开发者来扩展,且表示构成该工作流模型的闭合的原语集。语言被绑定到由工作流系统销售商发货的语言编译器。仅该工作流系统产品销售商可通过在该产品的未来版本中用一新的构造集扩展该语言来扩展该模型。这通常要求升级与该语言相关联的编译器。基于应用程序的方法是这样一种应用程序,它在该应用程序内具有工作流能力以解决领域专用问题。这些应用程序不是真正可扩展的,也没有可编程模型。采用现有方法,复杂性、预知、动态工作流、创作简易性以及与商业逻辑和核心工作流的关联强度等问题未被充分地解决。没有可扩展、可定制以及可重新主宿工作流设计器框架可用于构建可视工作流设计器来对不同的工作流类别建模。现有系统缺乏一种快速应用程序开发(RAD)风格工作流设计体验,它允许用户图形地设计工作流过程,并以开发者选择的编程语言来关联商业逻辑。另外,没有启用了墨迹的工作流设计器。另外,现有系统无法提供用于执行工作流的无缝特别或动态编辑。工作流过程在本质上是动态且移动的,且其形式不能在设计时完全预见。该工作流过程以结构化方式起始,并最终在其执行生命周期过程中发展和改变。需要一种允许工作流构建者能够在设计时创作各种类型的工作流模型,以及以无缝的方式对运行的工作流做出特别或动态改变的工作流创作框架。即使在部署了工作流过程之后且该工作流过程正在运行,商业需求的变化通常迫使改变或编辑当前运行的工作流过程。需要一种提供工作流过程的运行时创作的系统。另外,工作流过程处理跨越工作流过程模型的多个步骤的横切的、互不相关且紊乱的问题。例如,尽管工作流过程的各部分被设计成参与长期运行的事务,然而同一过程的其它部分被设计成用于并发执行。同一工作流过程的另外一些部分要求跟踪,而其它部分处理商业或应用程序级例外。需要向工作流过程的一个或多个部分应用特定的行为。某些工作流建模方法是不实用的,因为它们需要整个商业过程的基于流的完整描述,包括所有例外以及人类干预。这些方法中的一些提供了当出现例外时的附加功能,而其它方法独占地采用基于约束的方法而非基于流的方法来对商业过程建模。现有系统实现基于流或基于约束的方法中的任一种。这些系统该不灵活,以致于无法对许多常见商业情况进行建模。因此,需要一种组件化且可扩展的工作流模型来解决这些和其它缺点的一个或多个。
发明内容本发明的实施例提供了一种用于构建组件化工作流模型的可扩展框架。具体地,工作流过程中的每一步骤具有描述工作流步骤的设计时方面、编译时方面以及运行时方面的相关联组件模型。此外,任何开发者可通过创作这些组件来扩展核心工作流模型。本发明包括一工作流引擎,它足够灵活和强大来协调各种工作流的执行,包括高度形式的机器到机器过程、基于约束的特别人类工作流、以及具有基于流和基于约束的方法的混合的工作流。该工作流引擎准许对执行工作流的激活、执行、查询和控制能力。例如,本发明准许对执行工作流的特别和动态改变。该工作流引擎可以在包括服务器和客户机环境两者的各种宿主环境中重新主宿或嵌入。每一特定宿主环境将工作流引擎与一组服务提供者相结合。服务提供者的总能力确定了可在该特定宿主环境中执行的工作流的种类。本发明的其它实施例提供了一种用于序列化工作流模型的声明性格式,诸如可扩展配合(orchestration)标记语言(XOML)。该声明性格式使用户能够通过编写一组组件来扩展工作流模型。对应于工作流过程的各步骤的语义被封装在活动确认器组件中,该组件在编译时确认并实施给定组件的语义。本发明的声明性格式的实施例还能够进行数据声明以及与工作流模型的各元素的数据相关。该声明性格式支持数据通过工作流的变换。例如,该格式声明性地表示外部数据源,如数据库或文件、代码片断以及工作流模型内的商业规则。本发明的一个实施例提供了一种构建图形/可视工作流设计器的可扩展、可定址以及可重新主宿的工作流设计器框架,以对不同类别的工作流建模。本发明的另一实施例支持快速应用程序开发风格的工作流设计体验,以允许用户图形地设计工作流过程,并以任何编程语言来关联商业逻辑。本发明的实施例也使用笔和图形输入板技术提供了墨迹支持。本发明提供了一种自由形式的绘图表面,其中,由用户绘制的工作流被转移到内部表示。本发明支持通过在现有绘图表面上的墨迹编辑(例如,添加/删除活动)以及现有工作流的墨迹注释(例如,书写表面上的注解、建议或提醒等手绘物)对工作流的创建和修改。本发明的其它一些实施例提供了用于以声明性方式捕捉横切行为并将行为应用于工作流模型的选中部分的组件。本发明的其它实施例在与其相关联的行为的上下文中执行工作流模型的选中部分。本发明的实施例提供了处理工作流模型的多个步骤的横切的、互不相关且紊乱的问题的框架、可重新使用组件和语言。按照本发明的一个方面,一种计算机实现的方法对工作流建模。该工作流包括活动,并且该工作流对商业过程建模。该方法包括呈现多个活动、接收用户对所呈现的活动的选择、以及序列化所接收的活动以创建工作流的持久表示。按照本发明的另一个方面,一个或多个计算机可读介质具有用于对工作流建模的计算机可执行组件。该工作流包括活动,并且该工作流对商业过程建模。组件包括用于呈现多个活动的选项板组件。组件还包括用于从用户接收对由选项板组件呈现的活动的选择和分层组织的接口组件。组件还包括用于序列化由接口组件接收的活动以创建工作流的持久表示的声明性组件。按照本发明的又一方面,一种计算机实现的系统对工作流建模。该工作流包括活动,并且该工作流对商业过程建模。该计算机实现的系统包括标识多个活动的包。该系统还包括用于从该包选择一个或多个活动并且使它们互相关连以创建工作流的接口。该系统还包括用于序列化所接收的活动以创建工作流的持久表示的序列化器。可替换地,本发明可包括各种其它方法和装置。其它特征将是部分地显而易见的,并且部分地在下文中指出。图1是包含任务和控制流合成活动的示例性工作流。图2示出了一个示例性活动继承树。图3示出了一个示例性组件模型。图4示出了一个示例性组件模型生命周期。图5是用于创作依赖于工作流规范的向导的工作流的高级应用程序用户界面。图6示出了一个示例性工作流设计器。图7示出了包括其后跟随着发送活动的接收活动的配合程序。图8以图表示出了对象的序列化。图9示出了在可视工作流、工作流的XOML序列化、以及工作流的分离代码之间的进度表定义和关系。图10是示出其中可实现本发明的合适计算系统环境的一个例子的框图。附录A描述了示例性活动。附录B描述了示例性活动设计器接口。附录C描述了活动确认。附录D描述了本发明的示例性应用程序编程接口。相应的参考标号在全部附图中表示相应的部分。具体实施例方式本发明的实施例对表示诸如商业过程等过程的工作流进行建模。商业过程是导致可预测和可重复结果的依赖性和有序的任务、活动等。包括组织的操作过程、机构的工作知识以及信息资源,商业过程被设计成以有效且及时的方式满足所定义的商业目标。在一个有效的环境中,过程的功能性组件可被容易地标识、适应和部署来解决不断改变的企业需求。工作流是与商业过程中的任务交互的最终用户的体验。任务被建模为活动、组件等,其每一个表示由个人或机器执行的工作单元。在一个实施例中,向用户呈现多个活动。用户选择并组织活动来创建工作流。执行所创建的工作流以对商业过程建模。首先参考图1,示例性工作流100包含任务和控制流合成活动。在一个示例中,配合引擎工作流模型支持不同类别工作流的建模、创作和执行。示例包括按照出现在有序序列中或作为一组异步事件出现的一组结构化步骤对给定问题建模。该配合引擎协调进度表的执行。进度表是以树形结构分层排列的一组经组织的活动。执行活动的执行上下文以及对其可见的共享数据由一作用域提供。每一活动表示封装工作流过程中步骤元数据的组件。活动是工作流模型中的基本执行单元,且具有相关联的属性、句柄、约束和事件。每一活动可以由任何编程语言中的用户代码来配置。例如,用户代码可表示以公用语言运行时环境(CLR)语言书写的商业或应用程序逻辑或规则。每一活动支持对用户代码中的执行的预截听(pre-interception)挂钩和后截听(post-interception)挂钩。每一活动具有相关联的运行时执行语义和行为(例如,状态管理、事务、事件处理和异常处理)。活动可与其它活动共享状态。活动可以是原语活动或被组合成合成活动。原语或基本活动没有子结构(例如,子活动),并由此是树结构中的叶节点。合成活动包含子结构(例如,它是一个或多个子活动的父节点)。在一个实施例中,活动有三种类型简单活动、容器活动和根活动。在本实施例中,在模型中有一个根活动,且根活动中没有或有任何数量的简单活动或容器活动。容器活动可包括简单或容器活动。整个工作流过程可用作构建更高阶工作流过程的活动。此外,活动可以是可中断或不可中断的。不可中断合成活动不包括可中断活动。不可中断活动缺少可导致活动阻断的服务。配合引擎提供一组示例性的活动。参考图2,一活动继承树示出了若干示例性活动。图2列出的示例性活动在附录A中详细描述。另外,任何用户可编写一个或多个活动来扩展工作流模型。例如,用户可为特定的商业问题、领域、工作流标准(例如,商业过程执行语言)或目标平台编写活动。配合引擎可向用户提供一组丰富的服务来编写活动,该组服务包括,例如分析代码、类型分解和类型系统的服务、用于序列化和呈现的服务。在一个实施例中,每一活动具有至少三个部分元数据、实例数据和执行逻辑。活动的元数据定义了可被配置的数据属性。例如,某些活动可共享在活动抽象基类中定义的一组公用元数据。每一活动依照其需求通过扩展该类来声明其自己的附加元数据属性。元数据属性的值由该活动跨配置该活动的进度表的实例的所有实例共享。例如,如果用户创建进度表A,并向其添加一发送活动,则该发送活动被给予标识信息(例如,“001”)作为其元数据的一部分。添加到该进度表的第二发送活动将接收其自己的唯一标识信息(例如,“002”)。一旦创建和执行了进度表A的多个实例,则发送“001”的所有实例将共享元数据值。相反,活动的实例元数据定义了一组对运行进度表实例中的活动实例专用的数据。例如,延迟活动可提供其实例数据上的只读属性,该实例数据是标识延迟活动的超时值的日期和时间值。一旦延迟活动开始执行,该值即可用,且它对延迟活动的每一单个实例很可能是不同的。通常参考进度表的实例,尤其是活动和任务的实例,而不用“实例”来限定参考。合成活动具有其子活动组作为另一元素。子活动在一个实施例中被认为是元数据。配合引擎模型明确地准许在运行时在进度表的实例中操纵该元数据。向作为执行进度表实例的一个部分的合成活动添加新的子活动,使得仅该进度表实例的元数据(活动树)被影响是可能的。接下来参考图3,每一活动具有一组相关联的组件,它们形成了该活动的组件模型。该组相关联的组件包括活动执行器、活动设计器、活动序列化器、活动确认器(例如,语义检查器)、以及活动代码生成器。活动执行器是实现该活动的执行语义的无状态(stateless)组件。活动执行器与活动的元数据一起工作来实现该活动。代码调度器担当活动执行器的服务提供者以向活动执行器提供服务。活动设计器可视地显示活动的设计时可视表示。活动设计器是设计器分层结构中的一个节点,并且可以加主题或加皮肤。活动设计器主宿在设计环境中(例如,应用程序),并通过服务与宿主设计环境交互。活动设计器接口在附录B中详细描述。活动确认器在编译时以及运行时实施活动语义。活动确认器在工作流模型的上下文中操作,并使用由该环境提供的服务(例如,编译器、设计器或运行时环境)。确认在工作流生命周期中的各个点发生。结构依从性检查在创建工作流的序列化表示时、编译时或响应于用户请求而做出。语义检查可以在运行时比在编译时执行的检查更强大,以确保诸如运行实例的活动树中活动的添加和替换等运行时操作的安全性。本发明评估与每一活动相关联的语义,以找出例如与预定接口要求的一致性和依从性。活动确认在附录C中详细描述。活动序列化器是序列化活动元数据的组件。活动序列化器从各种模型/格式序列化器中调用。整个工作流模型是基于一可扩展模式被序列化成声明性标记语言的,它可以按需进一步被转换成其它工作流语言。在一个实施例中,活动的组件模型作为数据结构储存在计算机可读介质上。在该数据结构中,活动设计器由储存用于可视地表示该活动的数据的图像字段(例如,图标)表示。另外,一个或多个创作时字段储存定义与活动相关联的属性、方法和事件的元数据。活动序列化器由储存用于将储存在创作时字段中的元数据传送到活动的声明性表示的数据的序列化器字段表示。活动生成器由储存与储存在创作时字段中的元数据相关联的软件代码的商业逻辑字段来表示。活动执行器由储存用于执行储存在商业逻辑字段中的软件代码的数据的执行器字段表示。作用域和进度表执行活动的执行上下文以及对其可见的共享数据由作用域来提供。作用域是核心活动之一。作用域是用于将变量和长期运行服务与事务语义、出错处理语义、补偿、事件处理程序和数据状态管理集合在一起的统一构造。作用域可具有相关联的异常和事件处理程序。在一个实施例中,作用域可以是事务的、原子的、长期运行的或同步的。在对用户变量的冲突读-写或写-写访问的情况下,向用户提供并发控制。作用域也是事务边界、异常处理边界以及补偿边界。由于作用域可以在进度表内嵌套,因此用不同作用域内相同的名字(即使作用域是嵌套的)来声明变量、消息、通道和相关集而没有名字冲突也是可能的。在进度表内嵌套的作用域只能在该进度表的上下文内执行。进度表可以被编译为应用程序(例如,独立的可执行实体)或库(例如,用于从其它进度表调用)。被编译为库的每一进度表有效地构成了可从其它进度表内调用的新活动类型。进度表的元数据包括参数的声明。一旦开发了进度表,可执行所开发的进度表的实例。激活和控制进度表实例的过程是由其中嵌入了配合引擎的宿主环境所决定的。配合引擎提供了可用于测试进度表的不提供必要服务的“简单宿主”。另外,配合引擎提供了一激活服务来促进同样由引擎和外部应用程序用于与服务环境(即,宿主)交互的“服务提供者”模型(例如,应用程序编程接口)的标准化。激活服务创建了特定进度表类型的进度表实例,并可任选地传递参数。进度表实例本质上是运行进度表实例的代理,并包括唯一地标识该实例的标识符、对进度表的元数据(活动树)的引用、以及挂起、恢复和终止实例的方法。激活服务也支持基于给定的进度表实例标识符找出进度表实例。代码分离(code-beside)作用域活动可具有包括用于该作用域活动的商业逻辑的相关联的代码分离类。由于进度表本身是作用域,因此进度表也可具有代码分离的类。在进度表内嵌套的作用域也可具有其自己的代码分离类。在作用域内嵌套的活动共享该作用域的代码分离类,它担当其共享数据的状态和商业逻辑的容器。例如,代码活动的元数据包括对具有代码分离中的特定签名的方法的引用。在另一实例中,发送活动的元数据包括对特定签名的代码分离方法的可任选引用加上对消息声明和通道声明的强制引用。代码分离的示例性使用包括变量、消息、通道和相关集的声明;出/入/引用参数的声明;附加自定义属性的声明;要发送的消息的准备;已接收消息的处理;以返回布尔值的代码表达的规则的实现;本地定义的变量的操纵;读活动元数据和实例数据;写活动实例数据(例如,设置将要执行的活动的属性);引发事件;抛出异常;枚举和导航运行进度表实例的活动树中的活动的分层结构,包括跨嵌套的作用域和进度表调用边界;向运行进度表实例内的合成活动添加新活动;改变与运行进度表实例内的活动相关联的声明性规则;以及获取对其它运行进度表实例的引用和对其的操纵。参考图4,一框图示出了一个示例性组件模型生命周期。用户与存储在一个或多个计算机可读介质上的计算机可执行组件交互。计算机可执行组件包括用于呈现多个活动的选项板组件402、用于接收对由选项板组件402呈现的活动的选择和分层组织的接口组件404、用于序列化由接口组件404接收的活动以创建工作流的持久表示的声明性组件406、以及用于将由声明性组件406序列化的工作流表示和由接口组件404接收的软件代码编译成包含工作流的可执行表示的单个程序集的运行时组件408。接口组件404包括用户界面(例如图形的)和/或应用程序编程接口(API)。用户与计算机可执行组件交互,以用诸如可扩展对象标记语言(XOML)等语言创建包括分离代码和串行化表示的工作流。运行时组件408生成程序集(例如,生成的代码、XOML和分离代码)并且执行该程序集。本发明支持对正在执行的工作流的特别修改,从而产生经修改的XOML。在另一个实施例中,本发明的计算机可执行组件提供一种用于创建与工作流相关联的进度表的进度表接口、用于创建与进度表相关联的作用域的作用域接口、以及用于选择一个或多个活动的活动接口。本发明排列所选择活动,以在用于在所创建的作用域内执行的所创建的进度表内创建工作流。在一个实施例中,进度表接口、作用域接口和活动接口是应用程序编程接口(API)。在一个编程对象模型中,编译在工作流中排列的多个活动包括,对该多个活动的每一个,通过元数据接口从与其相关联的组件模型接收元数据。接收元数据包括接收多个活动的每一个的属性、方法和事件。该方法还通过经由确认接口检查与所接收的元数据相关联的语义,来确认所接收的元数据。该方法还根据确认,经由代码生成器接口生成与所接收的元数据相关联的软件代码。所生成的软件代码经由代码编译接口编译。一个或多个计算机可读介质具有用于执行该方法的计算机可执行指令。在一个实施例中,本发明提供元数据接口、确认接口、代码生成器接口和代码编译接口中的一个或多个。工作流模板(stencil)工作流模板(例如,工作流样板或活动包)包括根活动和一组活动。模板可以是域或宿主专用的。模型的示例包括结构化的工作流模板、人类工作流模板以及非结构化的工作流模板。某些模板可以作为一组活动是“闭合的”,包括被设计成可能在特定的宿主环境中共同工作的一个或多个根。其它模板可能是“开放”到各种程度的。模板定义了其可扩展性点。例如,开发者编写CustomRoot(自定义根)和新的抽象CustomActivity(自定义活动),并声明包是CustomRoot加上从CustomActivity导出的任何活动。示例性BPEL或XLANG/S模板包括具有以下特征的根活动状态管理和事务中的参与具有相关联的事件和异常处理程序、支持合约第一模型、可被分析、并具有定义良好的激活和终止行为。示例性模板还包括一组消息通信专用活动(例如,Send(发送)和Receive(接收)及其变体),以及诸如Scope(作用域)、Loop(循环)、Condition(条件)、Listen(监听)和Throw(抛出)等其它结构化活动。一个示例性Halifax模板包括具有以下特征的根活动隐含状态管理、相关联的异常处理程序(0-n)、支持基于事件的模型、具有良好定义的激活行为、以及具有未定义的终止。根活动包含0-n个EventDriven(事件驱动)活动。每一EventDriven活动表示一个Halifax活动。每一EventDriven活动具有相关联的状态管理协议并在原子作用域内执行。设计器框架(用户界面)配合引擎提供了用于以WYSWYG方式设计各种类别的工作流模型的框架。例如,参考图5,一种用于创作工作流的高级应用程序用户界面依赖于工作流规范的向导。该框架包括使开发者能够编写可视工作流设计器的一组服务和行为。这些服务提供了呈现工作流过程的有效方式、支持用于绘制工作流的墨迹/图形输入板、以及支持诸如撤消/回复、拖/放、剪切/复制/粘贴、缩放、扫视、搜索/替换等设计器操作、书签、装饰、用于确认错误的智能标签、用于活动的有效拖动目标指示符、自动布局、视图分页、导航标记器、拖动指示符、具有页眉/页脚的打印和预览等等。通过这一用户界面,可构造包含任务和控制流合成活动(例如,顺序、并行和条件)的简单工作流。对规则规范(例如,条件分支逻辑、while循环逻辑)或数据流规范(例如,任务A的输出是任务B的输入)不要求代码输入(或依赖于现有的已编译代码)。进度表的序列化表示(包括规则和数据流)是自包含的,且在不需要代码分离的某些情形中完成。使用本发明的设计器框架,本发明的配合引擎包括一种快速应用程序开发(RAD)风格的可视工作流设计器,它支持以可视方式将软件代码与工作流模型相关联。工作流中的每一活动具有相关联的活动设计器。每一活动设计器是按照框架服务来编写的。本发明的框架也包含一可视设计器模型。该可视设计器模型包括通过该工作流模型中的关系彼此链接的一组活动设计器。图6示出了一个示例性工作流设计器。本发明包括将代码与工作流模型相关联的各种模式,包括“代码分离”、“代码嵌入”和允许用户代码实时在工作流模型中往返的“仅代码”。本发明也提供了当用户在构建工作流时的实时语义错误。在一个实施例中,本发明向用户呈现了标识设计器框架用户界面中的多个活动的包。本发明还从用户接收对所呈现的活动的选择和分层组织。本发明序列化所接收的活动来创建工作流的持久表示。本发明还从用户接收表示用于与工作流中的多个活动之一相关联的商业逻辑的软件代码。本发明也可接收具有与其相关联的一个或语义的用户定义活动。本发明包括用于评估语义以找出其对预定义接口要求的一致性的语义检查器或确认器。如果语义与预定义的接口要求相一致,则本发明呈现该用户定义的活动作为多个活动之一。本发明还编译软件代码来创建一个或多个二进制文件。例如,本发明将序列化的工作流表示和软件代码编译成包含工作流的可执行表示的单个程序集(assembly)。本发明执行所创建的工作流。在一个实施例中,一个或多个计算机可读介质具有用于执行该方法的计算机可执行指令。配合引擎设计器允许用户通过使用其它所创建的进度表来递归地组成更高阶进度表并使用它们。进度表的内联扩充允许用户内联地查看进度表内容并剪切或复制内容。为允许进度表的内联扩充以及使进度表只读,创建用于内联进度表的单独设计表面和设计器宿主。此外,合成进度表设计器具有其自己的分层结构。所调用的进度表在设计器由用户扩充时被加载和显示。在一个实施例中,当活动被放到或复制到设计器表面上时,层叠设计器。一属性将调用活动设计器与主宿的进度表的根设计器链接。以下函数防止向设计器添加或移除活动。internalstaticboolAreAllComponentsInWritableContext(ICollectioncomponents)internalstaticboolIsContextReadOnly(IServiceProviderserviceProvider)这些函数由基础结构调用以检查其中插入活动的上下文是否为可写的。对于主宿的设计器,这些函数返回假。另外,防止属性被修改。其它函数从适当的组件中取出活动设计器internalstaticServiceDesignerGetSafeRootDesigner(IServiceProviderserviceProvider)internalstaticICompositeActivityDesignerGetSafeParentDesigner(objectobj)internalstaticIActivityDesignerGetSafeDesigner(objectobj)在一个示例中,用户创建进度表并将其编译为活动。在成功地编译之后,该进度表出现在工具箱中。用户打开或创建其中需要所编译的进度表的进度表。用户从工具箱中拖放所编译的进度表。在设计表面上示出层叠的进度表设计器。当用户希望查看放下的所编译的进度表的内容时,用户扩充进度表设计器以用只读的状态示出内联的所调用的进度表的内容。所调用的进度表的内联使用户能够查看所调用的进度表,而无需在不同的进度表设计器之间切换。该特征对于通过重复使用现有进度表来组成更高阶进度表的开发者而言是有用的。对使用主题/皮肤的设计器框架的定制的支持使用设计器框架编写的工作流设计器可使用工作流主题来定制。这些可以是声明性地描述设计器的各方面的可扩展标记语言(XML)文件。工作流设计器提供伙伴扩展活动的向导支持。工作流设计器支持的示例性用户界面特征包括,但不限于,撤消/恢复、拖/放、剪切/复制/粘贴、缩放、扫视、搜索/替换、书签、装饰、用于确认错误的智能标签、用于活动的有效拖动目标指示符、自动布局、视图分页、导航标记器、拖动指示符、具有页眉/页脚的打印和预览、以及文档大纲综合。工作流设计器支持自定义的设计器主题/皮肤来允许使用XML元数据定制设计器的外观和感觉。工作流设计器支持后台编译。在一个实施例中,提供了在设计进度表时用于确认错误的智能标签和智能动作。工作流设计器可主宿在任何容器中(例如,应用程序、外壳等)。一个示例性配合引擎程序包括接收活动以及其后跟随的发送活动。该过程接收消息并将其发送出去。用户创建名为“HelloWorld”的项目,并向该项目添加配合项。用户然后将作用域活动拖放至设计表面。下一步,用户将接收活动以及其后的发送活动放到该作用域上。图7示出了设计器中的所得工作流700。每一活动设计器提供了对象模型上的用户界面表示。开发者能够直接对对象模型编程,并设置活动上的属性或使用该设计器。配合引擎设计器允许开发者从工具箱中选择活动并将其拖到设计器表面上。如果活动已被放置到进度表中并需要移动,则开发者能够选择它(通过点击它)并将其拖至它需要去往的进度表区域。如果开发者按住ctrl键并同时进行拖放,则做出所选中活动的副本。积极放置提供了可能的拖动点(目标)作为设计表面上的可视指示器。自动滚动也参与在拖放的上下文中。当处理大型进度表时,到当前不在视见区中的设计器区域的导航可通过将该活动拖向要放置的进度表区域来访问。拖放可跨统一项目中的进度表以及跨统一解决方案中的其它项目中的进度表得到支持。在活动被放置到设计表面上之后,开发者配置该活动。每一活动具有一组属性,开发者配置该属性以使进度表有效。这些属性可在属性浏览器中编辑。每一活动控制什么属性在属性浏览器中是可查看的。为帮助开发者配置各活动,设计器提供了各种对话框或“子设计器”。对活动的各属性调用每一对话框。配合引擎能够定制工具箱中呈现的活动。当开发者创建自定义活动或进度表时,最终的结果是程序集。使用对话框,开发者能够浏览程序集位置并选择该程序集以使其作为配合引擎活动出现。或者,开发者可将程序集放置在配合引擎安装路径中,且它作为配合引擎活动呈现。应用程序编程接口(API)在另一实施例中,本发明提供了用于执行各种工作流操作的应用程序编程接口(API)。本发明包括用于创作工作流的设计应用程序编程接口。设计应用程序编程接口包括用于创作工作流的装置以及用于选择一个或多个活动来创建该工具流的装置。本发明也包括用于编辑经由设计应用程序编程接口创作的工作流的编译应用程序编程接口。编译应用程序编程接口包括用于序列化工作流的装置、用于定制工作流的可视外观的装置、用于编译经由设计应用程序编程接口创作的工作流的装置、用于确认工作流的装置。本发明也包括用于将类型与工作流中的每一活动相关联的类型提供者应用程序编程接口。类型提供者应用程序编程接口包括用于将该类型与工作流中的每一活动相关联的装置,以及用于将一类型与工作流中的每一活动相关联的装置。附录D描述了示例性API。附录D中的API构成了用于创作工作流的示例性装置、用于选择一个或多个活动来创建工作流的示例性装置、用于序列化工作流的示例性装置、用于定制工作流的可视外观的示例性装置、用于确认工作流的示例性装置、用于编译工作流的示例性装置、以及用于将类型与工作流中的每一活动相关联的示例性装置。活动执行框架由于有进度表和作用域的例外,因此引擎将活动视为抽象的实体,并仅协调活动的执行而不知道任何特定活动的具体数据或语义。在一个实施例中,四个实体在活动的执行期间交互活动本身、正在执行的活动的父活动、包含正在执行的活动的作用域、以及配合引擎。每一实体具有不同的功能。如果活动的执行方法返回而没有向其活动协调器发信号通知完成,则该活动被认为是在逻辑等待状态中。这一活动可由配合引擎取消,或继续(例如,一旦它所等待的项或事件变得可用或发生,且由引擎向该活动通知这一情况)。某些从未进入逻辑等待状态的活动可能从不被取消。示例包括发送活动和代码活动,因为它们不需要对外部事件或预定的需求就可执行。一旦交出了线程(即,一旦其执行方法由配合引擎调用),则这些活动将做工作直到完成。从不给配合引擎取消它们的机会,因为它们不返回线程直到它们发信号通知完成。配合引擎运行时环境使用规则来触发在其上执行配合引擎活动的事件。配合引擎设计器向用户提供了在运行时关联要评估的规则来触发事件的能力。配合引擎设计器通过提供可扩展性体系结构使用户能够使用不同类型的规则技术。该设计器对于所使用的规则技术的类型是不可知的。在一个实施例中,设计器支持布尔表达式处理程序,作为将规则与活动相关联的一种方式。这意味着在用户代码文件中,用户编写返回真或假值的方法,基于该方法触发规则。当前有多种可用于评估规则的技术,包括信息代理(InfoAgent)和商业规则引擎(BRE)。为实现这一目标,设计器包括使规则技术开发者能够在设计器中主宿自定义用户界面的可扩展性体系结构。该设计器提供了一种自定义用户界面编写者以代码语句集合的形式序列化规则的方法。该设计器在用户代码文件中发放布尔处理程序,并向其插入代码语句集合。配合引擎包括可由规则编写者使用的默认用户界面。规则技术提供者通过创建自定义规则声明、编写与自定义规则声明相关联的用户界面类型编辑器、创建自定义用户界面来主宿规则用户界面、以及在保存时生成代码语句来向配合引擎设计器添加规则。在一个示例中,用户选择要向其附加规则的活动设计器、在属性浏览器中定位规则属性并在下拉框中选择“RuleExpressionHandler(规则表达式处理程序)”(它使得“Statements(语句)”属性出现在用户界面的Rule(规则)属性下方)、在“Statements”属性中指定用户代码方法名、调用用户界面类型编辑器来调用主宿规则专用用户界面的对话框、以及在对话框中通过创建新的谓词行并将它们组合在一起来定义规则。用户界面在用户代码文件中发放方法。方法名将与由用户在属性浏览器中指定的名称相同。等效于创建规则的代码语句将被插入到该规则的用户代码方法中。执行期间的消息通信在运行工作流中,发送到进度表的消息是预期供特定进度表实例使用的。例如,购买定单#123的发票必须被发送回发起(例如,发送出)该购买定单的同一进度表实例。为将入站消息与适当的进度表实例相匹配,消息和进度表实例共享一相关集。该相关集可以是单值相关集,这意味着消息中的标识符字段与由进度表实例持有的相同类型的标识符进行匹配。多属性相关集也是可能的,且类似于数据库表中的多列主要关键字。进度表实例持有的相关集的值是在进度表实例发送出消息时初始化的(例如,可从出栈定单的标识符字段中取该值),或当进度表实例接收消息时初始化的。该相关集值然后是该进度表实例状态的一部分。当随后的入站消息到达时,进度表实例状态中保持的相关集值与由预期类型的入站消息所持有的标识符字段进行匹配。当找到匹配,则满足该相关集,且该消息被传递到进度表实例。尽管相关集的实现是由配合引擎和宿主环境所决定的,但是在一个实施例中,用户声明该相关集以使进度表实例能够正确工作。在另一实施例中,某些活动(例如,SendRequest(发送请求)/ReceiveResponse(接收响应)活动以及ReceiveRequest(接收请求)/SendReponse(发送响应)活动)与用户无关地设置相关集。由发送和接收活动执行各种各样的确认检查,以确保相关集是正确初始化和遵循的。执行工作流的动态编辑配合引擎提供了用于创作(以及随后可视化和执行)各种类型的工作流的框架。示例包括事件-条件-动作(ECA)风格的工作流或结构化工作流或规则驱动工作流。此外,不论是如何对工作流建模的,工作流都允许用户在设计时或甚至在工作流过程正在运行时以同一方式创作或编辑工作流,而无需重新编译该工作流过程。该框架允许用户以高保真度在运行时和设计时表示之间进行往返。特别(adhoc)改变是在运行时对过程模型做出的改变。用户可向运行的实例要求其进度表模型,并向该模型做出改变。例如,用户可按批添加、移除或替换活动,然后提交或回退批处理的改变。在一个实施例中,模型是在更新之后确认的。在本发明的许多工作流情形中,“设计时创作”和“运行时执行”之间的分隔存在模糊或甚至是消除。进度表实例有效地与其它实例共享为那些实例的进度表类型所定义的活动类型(元数据)树。但是一旦开始执行,任何进度表实例可通过添加新活动或操纵声明性规则在进行中改变。采取这一修改的进度表实例并“保存为”新进度表类型,或更一般地,仅从实例中恢复序列化的表示是可能的。即,运行的进度表实例可被序列化,然后将其带入任何设计器(例如,创作环境)或运行时可视化工具。此外,对于高级开发者而言,将进度表完全作为软件代码来创作是可能的。为直接创作进度表类型,开发者只需在该进度表的代码分离类的软件代码中包括称为InitializeScheduleModel(初始化进度表模型)的方法,然后用[ScheduleCreator](进度表创建器)元属性来标记该方法。在一个实施例中,该静态方法不采用任何参数,并返回一Schedule(进度表)对象。没有伴随的序列化文件,尽管可从所创建的Schedule对象中恢复该进度表的序列化表示。尽管这意味着可使用单个软件代码文件来开发进度表,然而可能不在该文件上执行确认检查。配合引擎编译确保作为进度表类型的基础的活动树的结构和语义有效性。在另一实施例中,编译和确认内部地运行,以产生所执行的实际类型,而不要求任何代码输入。进度表类型编译变为一种非常容易的过程,因为没有从编译时对象模型到运行时对象模型的转换。本质上,编译只需将进度表的对象模型表示与代码分离相组合以产生新类型。在一个实施例中,如果所编译的代码分离与对象模型中的活动所需求的相匹配,对特定的进度表可能完全没有任何基本需求来提供任何代码分离,或者代码分离可能已经以编译的形式(程序集)存在。当编译序列化进度表时,指向有效地担当该进度表的代码分离的现有已编译类型是可能的。创建该已编译类型的派生类型,且该新类型担当代码分离以确保创建了唯一的类型来表示该新进度表。序列化体系结构序列化基础结构提供了一种模块化的、格式中立且容易扩展的机制来序列化配合引擎活动树。图8以图表示出了对象的序列化。具体地,调用者(例如,应用程序或用户)向序列化管理器请求对象(或活动)A的序列化器。对象A的类型的元数据元属性将对象A绑定到所请求类型的序列化器。调用者然后要求序列化器序列化对象A。对象A的序列化器然后序列化对象A。对于在序列化时遇到的每一对象,序列化器向序列化管理器请求另外的序列化器。序列化的结果被返回給调用者。配合引擎组件模型中的每一活动可参与序列化。在一个实施例中,序列化器组件不是活动类本身的一部分。相反,该组件通过在与该活动相关联的类中注释序列化器元属性来指定。序列化器元属性指向用于序列化该活动类型的对象的类。在另一实施例中,活动类型的提供者组件覆盖了由该活动提供的默认序列化器。设计器序列化基于元数据、序列化器和序列化管理器。元数据元属性用于将类型与序列化器相关。“程序引导”元属性可用于安装为没有序列化器的类型提供序列化器的对象。序列化器是知道如何序列化特定类型或类型作用域的对象。对每一数据格式存在一基类。例如,可以有知道如何将对象转换成XML的XmlSerializer(XML序列化器)基类。本发明是独立于任何特定序列化格式的通用体系结构。序列化管理器是对用于序列化对象图的所有各种序列化器提供信息存储的对象。例如,五十个推想的图可具有五十个不同的序列化器,它们都生成其自己的输出。序列化管理器可由这些序列化器使用以在必要时彼此通信。在一个实施例中,与使用类属对象元数据的序列化器耦合的序列化提供者的使用提供了一种回叫机制,其中,给予对象向给定类型提供序列化器的机会。可通过诸如AddSerializationProvider(添加序列化提供者)等方法来向序列化管理器给予序列化提供者。序列化提供者可通过向序列化器添加诸如DefaultSerializationProviderAttribute(默认序列化提供者属性)等元属性而被自动添加到序列化管理器。在一个实施例中,格式由以下规则来规定对象被序列化为xml元素、对象的属性被归类为简单属性(例如,序列化为xml元属性)或复杂属性(序列化为子元素)、以及对象的子对象被序列化为子元素。子对象的定义可在各个对象之间不同。以下示例是while活动的序列化,它具有Send活动作为其子对象之一。<WhileID=″while1″><ConditionRule><CodeExpressionRuleDeclaration><ExpressionName=″whileCondition″/></CodeExpressionRuleDeclaration></ConditionRule><SendHasTypedChannel=″True″ID=″send1″><MessageName=″msg1″Type=″System.UInt32″/><OnBeforeSendName=″onBeforeSend1″/><TypedChannelType=″System.Collections.IList″Operation=″AddIndex″Name=″Foo″/></Send></While>在其中用于序列化的语言是XOML的实施例中,当编译进度表时,每一XOML元素被序列化成其各自的对象。对象包括简单和复杂类型两者。接下来描述每一活动的XOML表示之间的映射及其到创作对象模型的映射。XOML的序列化在原语(Primitive)和合成(Composite)活动之间有所不同。原语活动的简单类型被序列化为该活动类型上的元属性。原语活动的复杂类型被序列化为子元素。作为一个示例,以下是Send活动的XOML表示。<SendID=″send1″HasTypedChannel=″False″><MessageName=″message1″Type=″System.String″/><UntypedChannelName=″c1″/></Send>以与原语类型序列化类似的方式,合成活动的简单类型被序列化为该活动类型上的元属性。然而,按照定义,合成活动封装了嵌套的活动。每一嵌套的活动被序列化为另一子元素。作为一个示例,以下是While活动的XOML表示。<WhileID=″while1″><ConditionRule><CodeExpressionRule><ExpressionName=″test″/></CodeExpressionRule></ConditionRule></While>过程/工作流视图和序列化的表示之间存在强关系。图9示出了可视工作流、该工作流的序列化(例如,XOML)表示以及该工作流的分离代码之间的进度表定义和关系。当以任一表示创作时,其它表示将招致改变。由此,当开发者在XOML和过程/工作流视图之间切换时,修改活动的XOML(或在合成活动的情况下修改其构成部分)直接在过程/工作流视图中得到反映。反过来也是适用的。修改过程/工作流视图中的活动导致XOML内的适当修改。作为一个示例,过程/工作流中的活动的删除导致同一活动的XOML中XML元素的移除。在过程/工作流视图和分离的代码之间也发生往返。在创建XOML代码的过程中,如果XOML定义不符合预定义的接口要求,则在违反的XML元素下加下划线,或用其它方式可视地向开发者标识。如果开发者切换到过程视图,则将向他们警告在XOML内存在错误,且设计器提供一链接,开发者可点击该链接并且会被导航到违反的元素。该同一错误出现在任务面板中,并且在双击该错误之后,开发者将会被导航到XOML中违反的元素。从XOML文件创建活动树(反序列化)在一个实施例中,CreateEditorInstance()函数(创建编辑器实例)创建DesignSurface(设计表面)对象,然后对DesignSurface对象调用BeginLoad()函数(开始加载),向其传递实际的加载器对象,最终以对DesignerLoader()函数(设计器加载器)的BeginLoad()调用而结束。PerformLoad()函数(执行加载)读取文本缓冲区对象,并将其反序列化到配合引擎组件模型分层结构。本发明走查该分层结构,并将活动插入到设计表面以加载视件工作室(visualsutdio)中的组件。本发明也监听对XOML文件的改变以跟踪分层结构和项标识改变,来更新视件工作室高速缓存中的值。次要文档数据列表包括对用户不可见的次要文档的列表,配合引擎设计器在这些次要文档上工作。例如,用户尚未打开分离代码文件,但当用户在配合引擎设计器中做出改变时,对该分离代码文件做出改变是可能的。由于该文件对用户是不可见的,因此该文件作为次要文档来维护。只要保存XOML文件,就自动保存次要文档。如果这些文件之一的名字改变,或者文件被删除,则本发明相应地更新对应的次要文档对象。对象树的示例性反序列化准则如下。xml元素首先作为父对象的属性来处理。如果父对象没有具有该元素标签名的属性,则该元素作为父对象的子对象来处理。xml元属性作为父对象上的简单属性来处理。在适用上述序列化代码的一个示例性反序列化中,<While>元素作为适用xml名字空间信息创建的对象来处理。<ConditionRule>元素作为While活动的属性来处理。<CodeExpressionRuleDeclaration>元素作为其值将被应用于ConditionRule属性的对象来处理。<Send>元素首先作为While活动的属性来尝试,但“While”活动没有具有名字为“Send”的属性,因此<Send>元素作为对象来处理,并作为子活动添加到while活动。<Message>元素作为Send活动的属性来处理。由于Send上的Message属性是只读的,因此Message元素的内容被认为是Message对象的内容。类似的规则也适用于<OnBeforeSend>和<TypedChannel>元素的反序列化。在以下条件下,XOML反序列化将会严重失败XOML代码不是良好形成的、XomlDocument不是XOML代码中的第一个元素、以及XOML代码中的第一个活动不能被反序列化。将向开发者呈现出错消息,当从XOML视图切换到过程/工作流视图时,通过该消息他们可被导航到违反的XML元素。主宿配合引擎设计器设计器框架可被主宿在任何应用程序中。这对于第三方应用程序要在其各自的环境中呈现工作流而言是非常有用的特征。它也允许第三方通过重新主宿和定址设计器表面来开发关于配合引擎设计器的工具。本发明的框架期望主宿容器应用程序能够提供诸如编辑器和/或文本缓冲区等一组服务。重新主宿设计器的一个步骤是创建加载器和设计表面。加载器负责加载XOML文件,并构造维护活动的设计器宿主基础结构。设计表面维护其中的设计器宿主基础结构,并向宿主提供服务且与设计表面交互。设计表面担当服务容器以及服务提供者。在一个示例中,执行以下代码来加载XOML文档并构造维护其中的活动的设计器宿主。this.loader.XomlFile=filePath;if(this.surface.IsLoaded==false)this.surface.BeginLoad(this.loader);以下服务启用了设计器中的不同函数。ISelectionService函数(选择服务)维护所选中的对象。IToolboxService函数(工具箱服务)管理与工具箱的交互。IMenuCommandService函数(菜单命令服务)管理与菜单的交互。ITypeProvider函数(类型提供者)启用类型系统。另外,可以有由设计器主宿环境提供的其它服务,以启用高级的设计器特征。类型流是本发明的组件模型框架中的一个组件。当设计器主宿在项目系统内部时,在每一项目的基础上创建TypeProvider(类型提供者)对象。项目中的程序集引用被压入类型提供者。此外,对项目中的用户代码文件进行语法分析,并创建单个代码编译且将其压入类型提供者。另外,本发明监听项目系统中将导致类型系统中的类型改变的事件,并响应于改变对类型提供者做出适当的调用来重新加载类型。撤消/恢复在创建且正确地构造了进度表之后,开发者可能希望回退一系列已执行的操作。本发明的撤消和恢复功能提供了可视的反馈,它示出了哪一活动被直接影响。例如,当撤消活动上的属性时,被影响的活动变为选中。当撤消多个对象的删除时,当被恢复到进度表时,所涉及的所有对象变为选中。撤消/恢复是在其它领域的许多应用程序中使用的常见特征,且其意义是被普遍理解的。在配合引擎设计器中,撤消/恢复项在保存时不被清除。此外,撤消/恢复可在过程/工作流视图中、XOML视图中、当开发者在视图之间切换时、以及在分离代码中执行。对过程/工作流视图中的以下动作提供了撤消/恢复活动拖放(例如,将活动从工具箱拖到设计表面、将活动从进度表的一部分移到另一部分、以及将活动从一个设计器移到另一设计器)、活动的配置(例如,指定活动的属性)、以及剪切/复制/粘贴/删除。在一个实施例中,序列化的视图(例如,XOML)视图是提供文本编辑器的标准撤消/恢复操作的XML编辑器。本发明的设计器向开发者提供了反馈,指示过程/工作流视图中做出改变然后在序列化视图中撤消将导致序列化代码的丢失。当开发者在过程/工作流视图中构造进度表的一部分时,切换到序列化视图然后决定执行撤消/恢复操作,将出现警告。示例性操作环境图10以计算机130的形式示出了通用计算设备的一个示例。在本发明的一个实施例中,诸如计算机130等计算机适用于此处所示和所描述的其它附图。计算机130具有一个或多个处理器或处理单元132以及系统存储器134。在所示的实施例中,系统总线136将包括系统存储器134的各种系统组件耦合至处理器132。总线136表示若干类型总线结构的任一种的一个或多个,包括存储器总线或存储器控制器、外围总线、加速图形端口、以及使用各种总线体系结构的任一种的处理器或局部总线。作为示例而非局限,这类体系结构包括工业标准体系结构(ISA)总线、微通道体系结构(MCA)总线、增强ISA(EISA)总线、视频电子技术标准协会(VESA)局部总线以及外围部件互连(PCI)总线,也称为Mezzanine总线。计算机130通常具有至少某种形式的计算机可读介质。计算机可读介质可以是可由计算机130访问的任何可用介质,可包括易失性和非易失性介质、可移动和不可移动介质。作为示例而非局限,计算机可读介质包括计算机存储介质和通信介质。计算机存储介质包括以用于储存诸如计算机可读指令、数据结构、程序模块或其它数据等信息的任一方法或技术实现的易失性和非易失性,可移动和不可移动介质。例如,计算机存储介质包括RAM、ROM、EEPROM、闪存或其它存储器技术、CD-ROM、数字多功能盘(DVD)或其它光盘存储、磁盒、磁带、磁盘存储或其它磁存储设备、或可以用来储存所期望的信息并可由计算机130访问的任一其它介质。通信介质通常具体化为诸如载波或其它传输机制的已调制数据信号中的计算机可读指令、数据结构、程序模块或其它数据,并包括任一信息传送介质。本领域的技术人员熟悉已调制数据信号,它以对信号中的信息进行编码的方式设置或改变其一个或多个特征。有线介质,如有线网络或直接连线连接,以及无线介质,如声学、RF、红外和其它无线介质,都是通信介质的示例。上述任一的组合也应当包括在计算机可读介质的作用域之内。系统存储器134包括易失性和/或非易失性存储器形式的计算机存储介质。在所示的实施例中,系统存储器134包括只读存储器(ROM)138和随机存取存储器(RAM)140。基本输入/输出系统142(BIOS)包括如在启动时帮助在计算机130内的元件之间传输信息的基本例程,通常储存在ROM138中。RAM140通常包含处理单元132立即可访问或者当前正在操作的数据和/或程序模块。作为示例而非局限,图10示出了操作系统144、应用程序146、其它程序模块148和程序数据150。计算机130也可包括其它可移动/不可移动、易失性/非易失性计算机存储介质。例如,图10示出了对不可移动、非易失性磁介质进行读写的硬盘驱动器154。图10也示出了对可移动、非易失性磁盘158进行读写的磁盘驱动器156以及对可移动、非易失性光盘162,如CDROM或其它光介质进行读写的光盘驱动器160。可以在示例性操作环境中使用的其它可移动/不可移动、易失性/非易失性计算机存储介质包括但不限于,磁带盒、闪存卡、数字多功能盘、数字视频带、固态RAM、固态ROM等等。硬盘驱动器154、磁盘驱动器156和光盘驱动器160通常通过非易失性存储器接口,如接口160连接到系统总线136。上文讨论并在图10示出的驱动器及其关联的计算机存储介质为计算机130提供了计算机可读指令、数据结构、程序模块和其它数据的存储。例如,在图10中,示出硬盘驱动器154储存操作系统170、应用程序172、其它程序模块174和程序数据176。注意,这些组件可以与操作系统144、应用程序146、其它程序模块148和程序数据150相同,也可以与它们不同。这里对操作系统170、应用程序172、其它程序模块174和程序数据176给予不同的标号来说明至少它们是不同的副本。用户可以通过输入设备或用户界面选择设备,如键盘180和定位设备182(例如,鼠标、跟踪球或触摸垫)向计算机130输入命令和信息。其它输入设备(未示出)可包括麦克风、操纵杆、游戏垫、圆盘式卫星天线、扫描仪等等。这些和其它输入设备通常通过耦合至系统总线136的用户输入接口184连接至处理单元132,但是也可以通过其它接口和总线结构连接,如并行端口、游戏端口或通用串行总线(USB)。监视器188或其它类型的显示设备也通过接口,如视频接口190连接至系统总线136。除监视器188之外,计算机通常包括其它外围输出设备(未示出),如打印机和扬声器,它们可通过输出外围接口(未示出)连接。计算机130可以使用到一个或多个远程计算机,如远程计算机194的逻辑连接在网络化环境中操作。远程计算机194可以是个人计算机、服务器、路由器、网络PC、对等设备或其它普通网络节点,并通常包括许多或所有相对于计算机130所描述的元件。图10描述的逻辑连接包括局域网(LAN)196和广域网(WAN)198,但也可包括其它网络。LAN136和/或WAN138可以是有线网络、无线网络、其组合等等。这类网络环境常见于办公室、企业作用域计算机网络、内联网以及全球计算机网络(例如,因特网)。当在局域网网络环境中使用时,计算机130通过网络接口或适配器186连接至LAN196。当在广域网网络环境中使用时,计算机130通常包括调制解调器178或用于通过WAN198,如因特网建立通信的其它装置。调制解调器178可以是内置或外置的,它通过用户输入接口184或其它适当的机制连接至系统总线136。在网络化环境中,相对于计算机130所描述的程序模块或其部分可储存在远程存储器存储设备(未示出)中。作为示例而非局限,图10示出远程应用程序192驻留在存储器设备上。示出的网络连接是示例性的,也可以使用在计算机之间建立通信链路的其它装置。一般而言,计算机130的数据处理器通过在不同的时刻储存在计算机的各种计算机可读存储介质中的指令来编程。例如,程序和操作系统通常分布在软盘或CD-ROM上。从那里,它们被安装或加载到计算机的次级存储器中。在执行时,它们被至少部分地加载到计算机的初级电子存储器中。此处描述的本发明包括这些和其它各种类型的计算机可读存储介质,这些介质包含用于实现以下结合微处理器或其它数据处理器描述的步骤的指令。当依照此处描述的方法和技术编程时,本发明也包括计算机本身。为说明起见,诸如操作系统等程序和其它可执行程序组件在此被示出为离散的框。然而,可以认识到,这些程序和组件在不同的时刻驻留在计算机的不同存储组件中,且由计算机的数据处理器执行。尽管结合包括计算机130的示例性计算系统环境来描述,然而本发明也可用众多其它通用或专用计算系统环境或配置来操作。该计算系统环境并非对本发明的使用作用域或功能提出任何局限。此外,该计算环境不应当被解释为对示例性操作环境中所示的组件的任一个或其组合具有任何依赖性或要求。可适用于本发明的公知的计算系统、环境和/或配置的示例可包括,但不限于,个人计算机、服务器计算机、手持式或膝上设备、多处理器系统、基于微处理器的系统、机顶盒、可编程消费者电子产品、移动电话、网络PC、小型机、大型计算机、包括上述系统或设备的任一个的分布式计算环境等等。本发明可以在诸如由一个或多个计算机或其它设备执行的程序模块等计算机可执行指令的一般上下文环境中描述。一般而言,程序模块包括但不限于,例程、程序、对象、组件、数据结构等等,它们执行特定的任务或实现特定的抽象数据类型。本发明也可以在分布式计算环境中实践,其中,任务由通过通信网络连接的远程处理设备来执行。在分布式计算环境中,程序模块可以位于包括存储器存储设备的本地和远程计算机存储介质中。软件体系结构上下文中的接口包括软件模块、组件、代码部分或其它计算机可执行指令序列。例如,接口包括访问第二模块的第一模块,以代表该第一模块执行任务。在一个示例中,第一和第二模块包括诸如由操作系统提供的应用程序编程接口(API)、组件对象模型(COM)接口(例如,用于对等应用程序通信)、以及可扩展标记语言元数据互换格式(XMI)的接口(例如,用于web服务之间的通信)。接口可以是紧耦合的同步实现,诸如Java2平台企业版(J2EE)中、COM或分布式COM(DCOM)示例。作为替换或除此之外,接口可以是松耦合的异步实现,诸如web服务中(例如,使用简单对象访问协议)。一般而言,接口包括以下特征的任一组合紧耦合、松耦合、同步和异步。此外,接口可以符合标准协议、专有协议或标准和专有协议的任一组合。此处描述的接口可以都是单个接口的一部分,或可以被实现为单独的接口或其中的任何组合。接口可以本地或远程地执行以提供功能。此外,接口可包括比所示或所描述的更多或更少的功能。此处所示和描述的方法的执行或实现的顺序不是关键的,除非另外指定。即,方法的各元素可以用任何顺序执行,除非另外指定,并且方法可包括比此处所解释的更多或更少的元素。例如,在本发明的范围内可以构想,可以另一元素之前、与其同时或在其之后执行特定元素。当介绍本发明或其实施例的元素时,冠词“一”、“一个”、“该”和“所述”意指存在一个或多个元素。术语“包含”、“包括”或“具有”旨在包括性的,且意味着除所列出的元素之外还可以有其它元素。鉴于以上内容,可以看到,可以实现本发明的若干目标并且可以达到其它有利的结果。由于可以在以上构造、产品和方法中做出各种改变而不脱离本发明的范围,因此预期以上描述中包含且在附图中示出的所有内容都应当在说明性而非限制性的意义上解释。附录A示例性活动及其示例性实现示例性活动包括下列Send(发送)、SendRequest(发送请求)、SendResponse(发送响应)、Receive(接收)、ReceiveRequest(接收请求)、ReceiveResponse(接收响应)、Code(代码)、Delay(延迟)、Fault(错误)、Suspend(挂起)、Terminate(终止)、InvokeSchedule(调用进度表)、InvokeSchedules(调用多个进度表)、InvokeWebService(调用web服务)、DotNetEventSource(.NET事件源)、DotNetEventSink(.NET事件宿)、Sequence(顺序)、Parallel(并行)、While、ConditionalBranch(条件分支)、Conditional(条件)、Constrained(约束)、ConstrainedActivityGroup(约束活动组)(CAG)、EventDriven(事件驱动)、Listen(监听)、EventHandlers(事件处理程序)、ExceptionHandler(异常处理程序)、ExceptionHandlers(多个异常处理程序)、Compensate(补偿)、CompensationHandler(补偿处理程序)、Scope(作用域)以及Schedule(进度表)。上面列出的活动类依赖于一组支持它们的元数据声明的类型。这些类型包括DataElement(数据元素)、LiteralElement(文字元素)、MemberDeclaration(成员声明)、VariableDeclaration(变量声明)、TypedVariableDeclaration(类型化变量声明)、MessageDeclaration(消息声明)、CorrelationSetDeclaration(相关性设置声明)、ChannelDeclaration(通道声明)、TypedChannelDeclaration(类型化通道声明)、HandlerDeclaration(处理程序声明)、TypedHandlerDeclaration(类型化处理程序声明)、RuleDeclaration(规则声明)、CodeExpressionRuleDeclaration(代码表达式规则声明)、DeclarativeExpressionRuleDeclaration(声明性表达式规则声明)、ParameterDeclaration(参数声明)、ParameterDeclarationCollection(参数声明集合)、ParameterBinding(参数绑定)以及ParameterBindingCollection(参数绑定集合)。另外,定义了一组标准委托类型,它们映射到某些活动要求作为元数据的代码分离方法的类型。另外,存在一组实用程序类,它们支持进度表的序列化[XOMLSerializer和相关的类型]和编译[XOMLCompiler和相关的类型]。存在一个实用程序wfc.exe(例如,“工作流编译器”),它是用于编译进度表的命令行工具。发送活动配合引擎提供用于发送消息的三个活动,其每一个解决一种不同的使用情况。另外,由于这三个活动共享某种元数据,所以定义一个抽象基类并且用作所有这三个活动的超类。SendBase(发送基)元数据■消息引用。■可任选的代码分离方法。■可任选的相关集的集合。Send元数据○消息引用。○可任选的代码分离方法。○可任选的相关集的集合。■出站通道引用,它可以是非类型化或者类型化的。如果通道是类型化的,则在通道声明上也指定操作执行Send活动在指定的通道上发送指定的消息。如果使用类型化的通道,则Send活动使用特定的操作。该操作必须被定义为返回void(空)。非类型化的通道接受任何类型的消息。在发送消息之前,调用可任选的代码分离处理程序。该处理程序的正常用途是初始化或者准备将要发送的消息。Send活动还初始化指定的任何相关集。Send活动不遵循相关集。Send以同步方式执行(它不让步其线程,直到它完成)。SendRequest目的发送请求消息作为请求-响应消息模式的一部分。元数据○消息引用。○可选的code-beside(代码-在旁边)方法。○可选的相关集的集合。■出站通道引用,它可以是非类型化或者类型化的。如果通道是类型化的,则还指定操作执行SendRequest活动在指定的通道上发送指定的消息。如果使用类型化的通道,则Send活动使用特定的操作。该操作必须被定义为返回非void的类型(注意这是SendRequest与Send不同之处)。非类型化的通道接受任何类型的消息。在发送消息之前,调用可任选的代码分离处理程序。该处理程序的正常用途是初始化或者准备将要发送的消息。SendRequest活动还初始化指定的相关集。在一个只包含SendRequest/ReceiveResponse对并且没有其它接收活动的简单进度表中,不需要显式地创建或者初始化相关集;请求与响应消息的相关将自动执行。Send活动不遵循相关集。SendRequest以同步方式执行(它不让步其线程,直到它完成)。SendRestonse目的发送响应消息作为请求-响应消息模式的一部分。元数据○消息引用。○可任选的代码分离方法。○可任选的相关集的集合。■ReceiveRequest活动的ID。执行SendResponse活动在相关联的ReceiveRequest活动上声明的通道上发送指定的消息。如果使用类型化的通道,则SendResponse活动使用ReceiveRequest指示的操作。该操作必须被定义为返回一个非void的类型。非类型化的通道接受任何类型的消息。在发送消息之前,调用可任选的代码分离处理程序。该处理程序的正常用途是初始化或者准备将要发送的消息。SendResponse活动还初始化指定的任何相关集。Send活动不遵循相关集。SendResponse以同步方式执行(它不让步其线程,直到它完成)。接收活动配合引擎提供用于接收消息的三种活动,其每一个解决不同的使用情况。另外,因为这三种活动共享某种元数据,因此定义一个抽象基类并且用作所有这三种活动的超类。ReceiveBase目的接收活动的抽象基类。元数据■消息引用。■可任选的代码分离方法。■可任选的相关集的集合。Receive目的接收消息。元数据○消息引用。○可任选的代码分离方法。○可任选的相关集的集合。■表示这是否为激活接收的布尔类型。■入站通道引用,它可以是非类型化或者类型化的。如果通道是类型化的,则还指定操作。执行Receive活动为在指定通道上消息的到达执行阻塞等待。如果使用类型化的通道,则Receive等待通道的特定操作上的特定类型消息的到达。该操作必须被定义为返回void。非类型化的通道传送任何类型的消息。如果Receive是激活接收,则将配置一特殊的预订,使得在所指示通道上消息的到达将引起进度表的新实例的创建和执行,Receive是该进度表的一部分。Receive要遵循的相关集用在通道上建立的消息预订中。这确保进度表实例只接收以该实例为目标的那些消息。在接收消息之后,Receive活动初始化被指定为需要初始化的任何相关集。然后,调用可任选的代码分离处理程序。该处理程序的正常用途是以某种方式处理消息。ReceiveRequest目的接收请求消息作为请求-响应消息模式的一部分。元数据○消息引用。○可任选的代码分离方法。○可任选的相关集的集合。■表示这是否为激活接收的布尔类型。■入站通道引用,它可以是非类型化或者类型化的。如果通道是类型化的,则还指定操作。执行ReceiveRequest活动为指定通道上消息的到达执行阻塞等待。如果使用类型化的通道,则ReceiveRequest等待通道的特定操作上的特定类型消息的到达。该操作必须被定义为返回非void的类型(这是ReceiveRequest不同于Receive之处)。非类型化的通道传送任何类型的消息。如果ReceiveRequest是激活接收,则将配置一特殊的预订,使得在所指示通道上消息的到达将引起进度表的新实例的创建和执行,ReceiveRequest是该进度表一部分。ReceiveRequest要遵循的相关集用在通道上建立的消息预订中。这确保该进度表实例只接收以该实例为目标的消息。在接收消息之后,ReceiveRequest活动初始化被指定为需要初始化的任何相关集。然后,调用可任选的代码分离处理程序。该处理程序的正常用途是以某种方式处理消息。在一个只包含ReceiveRequest/SendResponse对且没有其它接收活动的简单进度表中,不需要显式地创建或者初始化相关集;请求与响应消息的相关将自动执行。ReceiveResponse目的接收响应消息作为请求-响应消息模式的一部分。元数据○消息引用。○可任选的代码分离方法。○可任选的相关集的集合。■SendRequest活动的ID。执行ReceiveResponse活动执行对在相关联的SendRequest活动上指定的通道上的消息的到达的阻塞等待。如果使用类型化的通道,ReceiveResponse活动使用由SendRequest活动指示的操作。该操作必须被定义为返回非void的类型。非类型化的通道传送任何类型的消息。ReceiveResponse活动不遵循相关集。在接收消息之后,调用可任选的代码分离处理程序。该处理程序的正常用途是处理所接收的消息。在接收消息之后,ReceiveResponse活动初始化被指定为需要初始化的任何相关集。然后,调用可任选的代码分离处理程序。该处理程序的正常用途是以某种方式处理消息。Code(代码)目的执行在分离代码中实现的方法。元数据■代码分离方法。执行Code活动执行在元数据中指示的代码分离方法。Code以同步方式执行(它不让步其线程,直到它完成)。因而,代码分离方法的执行是预期要完成的并且应该不因依赖于某种外部资源而阻塞。例如,该代码应该一般不调用web服务。Code活动的正常用途是检查进度表实例状态并且操纵局部变量和消息。Delay目的等待直到到达将来的一个特定的DateTime。元数据■返回DateTime的代码分离方法。实例数据■Delay正在等待(或者已经等待)的DateTime值。这个值被报告为空,直到Delay实际开始执行。执行Delay活动执行其强制性代码分离方法以生成DateTime值。它内部地将其实例数据上的TimeoutValue(超时值)属性设置为该值。如果DateTime是在过去,则Delay立即完成。否则,它设立定时器预订,使得Delay将在定时器激发时被通知。当定时器激发时,通知Delay并且它完成。与接收活动一样,Delay不同步地完成其执行;相反,它让步其线程,并且等待已经到达DateTime的通知。基于由引擎表面化的底层定时器服务的特征,保证Delay活动不会比所指示的DateTime早完成;但是,实际上它不会更长,因为定时器通知可在到达DateTime之后发生(例如,由于服务器环境中的高系统压力)。注意,必须返回UTC时间,以便Delay按预期那样工作;在很多情况下,这意味着在返回DateTime值的代码处理程序中使用DateTime.UtcNow来代替DateTime.Now。Fault目的抛出异常。元数据■返回Exception(异常)的代码分离方法。执行Fault活动执行其强制性代码分离方法,以生成Exception对象。它随后抛出这个异常。在功能上,Fault活动等价于Code活动,其代码方法只是抛出由ExceptionProvider(异常供应者)创建的异常。Fault的目的是捕捉商业异常的抛出,作为进度表的过程元数据的一部分。由于它抛出异常的事实,因此Fault活动将具有报告的有错误结果,尽管这构成了该活动的正常执行。Suspend目的暂停正在运行的进度表实例。元数据■报告给管理员的出错消息。执行Suspend活动挂起当前的进度表实例。它的意思是引擎立即停止处理对于为已经挂起的实例而排队的任何项的线程;没有“Cancel(取消)”信号出现。宿主(例如,实例管理器和持久供应者)决定出错消息去哪里。Terminate目的终止正在运行的进度表实例。元数据■报告给管理员的出错消息。执行Terminate活动终止当前的进度表实例。它的意思是,与Suspend相似,引擎立即停止处理对于为已经终止的实例而排队的项的线程。对于Terminate,排队的项也被删除,因为该实例没有可能被恢复进行。与Suspend相似,没有“Cancel”信号出现。宿主(例如,实例管理器和持久供应者)决定出错消息去哪里。InvokeSchedule目的调用进度表。元数据●要调用的进度表的类型。●表示调用具有CALL(调用)还是EXEC(执行)语义的枚举。●一组参数绑定。●在调用进度表之前调用的可任选代码分离方法。执行InvokeSchedule活动首先调用OnInitializeCallee(在初始化被调用者时)代码分离方法(如果已经指定了一个的话)。通常,该方法将用于设置要调用的进度表实例的In(输入)参数。InvokeSchedule随后创建和调用指定类型的进度表实例、传递所提供的参数。InvokeSchedule活动阻塞(并且让步其线程)(如果调用语义是CALL),并且等待被调用的进度表完成。或者,一旦进度表实例被调用,则InvokeSchedule活动立即完成(如果调用语义是EXEC的话)。InvokeSchedule调用OnCompletedCallee(在完成被调用者时)代码分离方法(如果已经指定了一个的话)。通常,该方法将处理所调用的进度表的Out(输出)参数。InvokeWebService目的调用web服务。元数据●用于调用web服务的代理类的名字。●要调用的web服务上的方法的名字。●表示调用是否为同步的布尔类型。●一组参数绑定。执行通过代理类调用web服务,传递和接收指定的参数。DotNetEventSink目的对通过RaiseEvent(引发事件)方法或者先前调用的(子)进度表内的DotNetEventSource活动引发的事件的处理建模。元数据●分离代码中的方法,它与在引发要处理的事件时所指示的委托类型相同。实例数据只有ActivityState(活动状态)。执行阻塞等待指定的事件已经由先前调用的进度表实例引发的通知。所调用的进度表实例必须在CALL语义下运行。DotNetEventSource目的对功能上等价于通过RaiseEvent方法引发分离代码中的事件的事件引发建模。元数据●委托类型,表示正被引发的事件类型(以及要求处理事件的事件处理程序类型)。●对在委托类型上定义的方法参数的参数绑定。执行引发指定的事件,并且立即完成执行。对于该个事件的预定者数量(可能是零或更多)没有保证,并且也没有用于从该事件的可能处理程序取回数据的机制,即语义是激发-忘记。Sequence目的按照单个定义的顺序执行一组子活动。执行Sequence活动协调一组子活动以有序的方式执行,一次一个。Sequence在最后一个子活动完成后完成。Parallel目的并发地执行一组子活动。执行Parrallel活动并发地执行一组子活动。启用子活动以供执行的顺序不是确定性的。Parrallel在所有子活动完成后完成。由于配合引擎的线程化模型,因此实际上在给定的时间点,在Parrallel内只有一个活动可以执行。While目的迭代地执行子活动。元数据●控制迭代的规则。执行迭代地执行子活动。在每次迭代之前(包括第一次),对规则求值;如果它求值为假,则While活动结束。ConditionalBranch目的表示一个Conditional的分支。元数据●控制被包装的活动的条件执行(分支)的规则。执行对每一Sequence语义执行子活动。父Conditional活动负责检查元数据(规则),以确定是否应执行ConditionBranch。Conditional活动本身没有提供附加的属性(除了ID和Description(描述)之外)。然而,Conditional由展示属性的条件分支组成。在选择了ConditionBranch后,两个附加的上下文菜单操作出现左移(将所选择的ConditionBranch移动到Conditional的直接左边)和右移(将所选择的ConditionBranch移动到Conditional的直接右边)。Conditional目的条件地执行n个ConditionBranch活动之一。执行Conditional活动包含一组有序的ConditionalBrahcn活动。Conditional执行其规则求值为TRUE(真)的第一个ConditionBranch活动。最后一个ConditionBranch活动允许不指定规则,在这种情况下它总是被认为求值为TRUE。对于一个Conditional,有可能还没有执行任何子活动就完成了。实质上,这提供了IF-ELSEIF-ELSE(如果-否则如果-否则)语义。Constrained目的为了将活动添加到CAG而包装该活动。元数据●被包装活动的启用规则。●被包装活动的禁用规则。运行时属性●表示被包装活动是否已经至少完成一次的整数。执行Constrained活动唯一被允许的父对象是CAG。CAG本身使用Constrained活动上的启用和禁用规则来确定何时执行它。当CAG告诉Constrained活动要执行时,它只是执行它所包装的活动。Performed(已执行)属性在Constrained活动结束其执行时递增。只有在父CAG本身被重新执行时(例如在WhileLoop或者第二个外部CAG内时)才被复位为零。CAG目的提供对一组子Constrained活动的基于约束的执行。元数据●完成规则。执行CAG只包含Constrained活动。当CAG执行时,它基于对其启用和禁用约束的求值执行(并且重新执行)子活动。子活动只有在其启用规则求值为真并且其禁用规则求值为假时才能由CAG执行。具体地CAG将步查其子树并预定对所有活动的活动状态改变;这将在调用边界停止。CAG将添加预订,只要活动被动态地添加到其子树。CAG将根据进度表边界预订对其包围的作用域和所有父作用域的数据改变;这些预订是通过分析CAG中所有Constrained活动上的启用和禁用规则来确定的。引擎将传送成批的数据改变通知,并且CAG将决定对哪些规则求值。注意,由被调用的进度表作出的数据改变在调用完成时发送。有可能标识作用域变量依赖性,即使那些变量是通过代码分离方法间接访问的。因此,有可能非常明确地确定在一个变量改变时应该重新对哪些约束求值。该同一机制将对声明性和代码规则两者起作用。如果Constrained活动没有启用规则,则它总是取为真。如果Constrained活动没有禁用规则,则它总是取为Performed>0。因而,如果在Constrained活动上没有指定规则,则在CAG执行时立即执行它,并且它永远不会被重新执行。同样,如果只在Constrained活动上提供一个自定义启用规则,则它将在启用规则求值为真时执行,并且它只执行那一次。如果需要基于约束的重新执行,则必须提供适当的自定义禁用规则,以及适当的启用规则。下面的表示出了执行Constrained活动所需的条件。表A1.Constrained活动执行如果在活动的执行期间,该活动的禁用规则求值为真,则CAG取消该活动的执行。这不排除该活动的重新执行。一旦CAG的完成规则求值为真,CAG立即取消任何当前正在执行的子活动,并且随后它自己完成。只要有必要,基于其数据和状态改变依赖性对所有规则(启用、禁用、完成)求值。CAG提供两种操作模式预览(Preview)和编辑(Edit)。如果CAG设计器处在预览模式,则开发者只能选择出现在幻灯片中的活动。属性浏览器在开发者选中任何活动时展示启用和禁用规则选项(下面详述)。这使开发者能够用CAG为每个活动设置启用和禁用规则。如果CAG设计器处在设计模式,则开发者能够在预览窗口中的活动(称为Constrained)上点击。属性浏览器随后除由特定活动正常展示的属性之外还显示启用和禁用规则选项(如在预览模式中)。CAG设计器提供少量附加的上下文菜单选项预览活动给定一个选中的活动,CAG将从设计模式切换到预览模式。编辑活动给定一个选中的活动,CAG将从预览模式切换到设计模式。查看前一的活动移动到紧靠幻灯片中当前选中的活动之前的活动。当到达CAG幻灯片中的第一个活动时,该菜单选项被禁用。查看下一的活动移动到紧靠幻灯片中当前选中的活动之后的活动。当到达CAG幻灯片中的最后一个活动时,该菜单选项被禁用。在一个实施例中,CAG内的每个活动被包装在一“Constrained活动”内。这随后通过CAG的幻灯片向开发者展示。如果CAG处在预览模式且开发者选中该活动并复制它,则可贴粘它的唯一地点(并且因而启用作为结果的上下文菜单)是在另一个CAG内。然而,如果开发者切换CAG模式到“设计”并且选择预览窗格内的活动,则以与其余的活动相似的方式启用复制/粘贴和拖放。Task目的对由一或多个委托者执行的外部工作单元建模。包装或者是InvokeSchedule或者是自定义活动的模板活动。元数据●执行模式,表示并行还是顺序执行。●底层任务实现的类型(称为模板)。●角色,表示任务的受托者。●可任选的代码分离方法,使开发者能够按每一受托者的基础设置任务属性。执行当执行任务时,首先将角色解析为一组委托者(受托者)。如果角色为空,则抛出异常。随后为每个受托者克隆模板活动一次,并且随后调用用于初始化这些克隆的属性的可任选代码分离方法(如果存在的话)(下面所示的例子)。取决于执行模式,随后并行或者顺序地执行各个受托者任务。为实现这一过程,每个受托者任务(克隆)被有效地包装在设置了适当的启用和禁用规则的Constrained活动中。注意,如果执行模式是顺序的,则顺序是按照由角色解析返回的受托者的排序来确定的。与CAG(任务的父活动)相似,如果完成规则变成真,则任务完成并且任何未完成的克隆被取消。否则,任务在所有受托者任务(克隆)完成时完成。EventDriven目的包装其执行是由“事件”活动触发的活动。执行EventDriven活动必须具有或者为Listen或者为EventHandlers合成活动的父活动。EventDriven活动包含IEventActivity(事件活动接口)和任何类型的第二活动两者。IEventActivity按照定义阻塞待决某一事件的发生,诸如定时器的激发或者消息的到达。当事件发生时,IEventActivity完成其执行,并且随后执行第二个活动。在选择一个EventDriven(一般在EventHandlers或者Listen活动内)后,两个附加的上下文菜单操作出现左移(将选中的EventDriven移动到Consitional中其直接左边)和右移(将选中的EventDriven移动到Conditional中其直接右边)。Listen目的有条件地执行n个子EventDriven活动之一。执行Listen活动确保其子EventDriven活动中仅令其IEventDriven(事件驱动接口)子活动的事件发生的第一个子活动被允许执行。所有其它的都被取消。在概念上,Listen与Conditional相似,因为只执行n个分支中的一个,其中分支的选择是由事件的发生而不是由程序上的商业逻辑来确定的。EventHandlers目的包装一组EventDriven活动。EventHandlers活动只保持一组EventDriven活动,以供相关联的Scope使用。EventHandlers活动只可与Scope相关联。ExceptionHandler目的用表示作用域捕捉块的元数据包装活动。元数据●表示捕捉块类型的枚举○All(全部)-捕捉所有异常○Type(类型)-捕捉指定类型的异常○Variable(变量)-捕捉指定类型的异常,并且使异常可用于检查分离代码的局部变量。●表示被捕捉的异常的类型的属性(仅在枚举设置为Type时使用)●对将存放异常的局部变量的引用(仅在枚举设置为Variable时使用)。执行在一个实施例中,ExceptionHandler活动只可添加到ExceptionHandlers活动。与ExceptionHandlers活动相关联的Scope使用关于其ExceptionHandler活动集的元数据来确定在Scope接收异常时要执行哪一个ExceptionHandler活动。当Scope告诉ExceptionHandler活动要执行时,它只执行它所包装的活动。在选择了ExceptionHandlers后,两个附加的上下文菜单操作出现查看前一活动、查看后一活动。ExceptionHandlers目的包装一组有序的ExceptionHandler活动。ExceptionHandler活动仅保持一组ExceptionHandler活动,以供相关联的Scope使用。在一个实施例中,ExceptionHandlers活动只可与Scope相关联。当两个或多个ExceptionHandler活动存在时,启用“左移”和“右移”上下文菜单选项。Compensate目的补偿已完成的子作用域。元数据●要补偿的子作用域的ID。执行Compensate活动只可在作用域的补偿处理程序或者异常处理程序中存在。其目的是触发已完成的子作用域的补偿处理程序。CompensationHandler目的包装被定义为作用域的补偿处理程序的子活动。执行执行其子活动。CompensationHandler活动只可与Scope相关联。Scope(作用域)目的作用域是事务边界;异常处理边界;补偿边界;事件处理边界;以及,消息、变量、相关集和通道声明(即共享的数据状态)的边界。作用域活动是用作逻辑容器的活动的分组。作用域的目的常常是将事务语义应用于所包围的活动集。元数据●作用域的代码分离类的类型。●表示作用域是否为同步作用域的布尔类型。●与作用域的事务特征有关的若干属性○事务类型无、原子的、或者长期运行的。○隔离等级(如果事务是原子的)■Chaos(混乱)来自较高程度隔离的事务的待决改变不能被盖写。■ReadCommitted(读提交)当正在读数据时保持共享锁以避免脏的读,但数据可在事务结束之前被改变,导致不可重复的读或者幻象数据。■ReadUncommitted(读未提交)脏的读是可能的,意味着不发布共享锁并且忽略排他锁。■RepeatableRead(可重复的读)在查询中使用的所有数据上设置的锁,防止其它用户更新数据。防止不可重复的读,但幻象行仍是可能的。■Serializable(可序列化的)在DataSet(数据集)上设置的范围锁,防止其它用户更新或者插入行到该数据集中,直到事务完成。■Snapshot(快照)通过存储一个应用程序在另一个应用程序正在修改数据时可读的同一数据版本来减少阻塞。表示从一个事务不能看到在其它事务中作出的改变,即使重新查询。■Unspecified(未指定)正在使用与所指定的不同的隔离等级,但不能确定该等级。○超时,单位秒(如果事务是原子的)○事务是否能够重试(如果事务是原子的)○事务是否是可成批(如果事务是原子的)○代码分离方法,返回表示超时值的DateTime(如果事务是长期运行)●在作用域开始执行时执行的代码分离方法。这本质上等价于作为作用域中的第一个活动的Code活动。保证该方法在作用域的任何事件处理程序可执行之前完成。这里,异常只作为作用域内的Code活动内的异常来对待。●在作用域结束执行时执行的代码分离方法。这几乎等价于作为作用域内的最后一个活动的Code活动;该代码将只在任何实例化的事件处理程序结束其执行之后才执行。这里,异常只作为作用域内的Code活动内的异常来对待。●一组可任选的事件处理程序。●一组可任选的有序异常处理程序(对于为原子事务的作用域不是有效的)。●可任选的补偿处理程序。执行Scope内活动的执行是顺序的,并且因而所包含的活动在构造作用域时被明确地排序,如在Sequence中。与其它合成类型相似,作用域可被嵌套,服从某些限制。如果开发者正在引用不是在作用域内声明的但用于该作用域内的任何属性的类型,则该属性将完全由属性浏览器内外部正在调用的进度表名字限制。在正常的环境下,Scope活动仅执行其“主(main)”子活动,以及其激发的事件处理程序中的任一个。如果指定OnScopeInitialized(在作用域被初始化时)代码分离方法,则执行该方法,就好象它是作为作用域内的第一项的Code活动。事件处理程序与Scope的“主”子活动并发地执行,并且被认为是Scope(作用域)执行的可任选的但正常的方面。如在Listen活动中,事件处理程序内的第一个活动必须是IEventActivity(事件活动接口)。通常,这或者是接收活动或者是Delay,但可以是实现适当接口的任何自定义活动。特定事件处理程序可对给定的Scope执行一次以上;并且,一个事件处理程序的这些实例有可能并发地执行。保证为激发每个事件处理程序的每个“事件”创建新实例。当Scope的“主”子活动完成其执行时,允许所有当前正在执行的事件处理程序实例正常地结束其执行。然而,随后不创建任何事件处理程序的新实例。如果指定OnScopeCompleted(在作用域被完成时)代码分离方法,则该方法在结束作用域的主体并且结束所有未完成的事件处理程序之后执行。本质上,作用域的OnInitialized(在被初始化时)和OnCompleted(在完成时)方法稳固地在作用域内。它们得到的唯一的“特殊对待”是●在OnInitialized方法完成之前没有事件处理程序可开始●在所有当前正在运行的事件处理程序(以及Scope的主体)完成之前不执行OnCompleted方法●一旦OnCompleted方法开始,没有事件处理程序还能运行在事件处理程序中发生的异常以与在Scope的“主”子活动中发生的异常完全一样的方式来对待。如果Scope被标记为同步的Scope,则这保证对共享数据的安全并发访问。同步的作用域不能被嵌套。访问相同的共享数据(对于两者都是外部)的同步作用域保证它们在该数据上的读/写操作不会与如果作用域是串行地执行而得到的结果不同。Scope还用作异常处理边界,意味着Scope的异常处理程序由作用域内所有嵌套的活动(包括任何事件处理程序)共享。如果异常是由非原子Scope内正在执行的活动抛出的,则作用域取消所有其它正在执行的活动和事件处理程序实例,并且如果它具有能够捕捉该异常的异常处理程序,随后处理该异常。一旦异常处理程序执行,则Scope完成,但具有Failed(失败)的结果。如果没有为特定异常类型的非原子作用域定义异常处理程序,或者如果异常处理程序抛出异常,则创建默认的处理程序(用于所有未被捕捉的异常),它以与子作用域的完成相反的顺序,运行那些子作用域的所有已安装的补偿处理程序(见下文),并且随后重新向其父Scope抛出异常。原子作用域不能具有相关联的异常处理程序。如果异常在原子作用域的执行期间发生,则事务失败,如该作用域的执行失败时一样。作用域将自己产生一个异常,该异常被传播到的确具有处理该异常的能力的下一个外部的包围作用域。其执行正常完成的Scope(指没有异常出现)“安装了”其补偿处理程序。随后通过Compensate活动,从父作用域的异常处理程序内,或者从父作用域的补偿处理程序内,可调用该补偿处理程序。如果没有为已完成的作用域定义补偿处理程序,则安装一个默认的补偿处理程序,它以与子作用域的完成相反的顺序运行那些子作用域的所有已安装的补偿处理程序。如上所述,补偿只在某一事件处理程序的上下文中发生。如果异常在补偿处理程序执行期间发生,则如在异常处理程序内的异常一样对待。除了标准的上下文菜单选项之外,Scope活动展示下列附加菜单选项查看作用域这是在添加到设计器时作用域的默认视图。选择这个选项使开发者回到这个视图。查看异常选择这个选项在原地改变UI以显示与该Scope相关联的异常。这只有在事务类型是长期运行或者是无时启用。换言之,该菜单在事务类型是原子时是不可用的。查看事件选择这个选项在原地改变UI以显示与该Scope相关联的事件处理程序。查看补偿选择这个选项在原地改变UI以显示用该Scope定义的Compensation。这仅当事务类型属性设置为长期运行或者原子时才启用。Schedule目的Schedule是配合引擎将执行的唯一的顶层活动。元数据(除Scope元数据之外)●进度表类型的名字空间。●CompilationType(编译类型)枚举,表示进度表是独立的应用程序,还是库(意味着从其它进度表调用)。●整个进度表的XOML格式的表示。●参数声明。执行除了消耗In(输入)和Optional-In(可任选的输入)参数并且产生Out(输出)参数之外,Schedule与Scope完全相同地执行。参数进度表元数据的一部分是参与其执行的参数集。合成活动启用控制流的合成活动是Sequence、Parallel、ConstrainedActivityGroup、Conditional、While、Listen。另外,Scope和Schedule是用作其中具有隐含的活动顺序的容器的合成活动类型。ID和描述属性每个活动提供ID和Description属性。当将活动从工具箱拖到设计表面时,自动生成该ID。Description属性是供开发者输入的占位符。典型的使用情况涉及开发者提供对于条件的特定分支可能用于什么内容的简短描述。在概念上,将该属性看作等价于VisualBasic和C#代码编辑器中的//。帮助文本当在属性浏览器中选择一个属性时,开发者能敲击F1键,并且索引到该属性的在线帮助。每个活动的每个属性将提供相关的帮助文本。任务错误列表和属性浏览器集成当活动的属性没有充分地配置时,向开发者呈现一个包含感叹号的图标。他们随后点击该图标并且看见配置错误的下拉列表。选择这些错误之一将把焦点移动到属性浏览器并且使错误的属性高亮。该图标将在活动的属性完成后消失。错误的配置也可在“任务列表”中看到。双击任务列表中提供的出错消息将开发者直接带到属性浏览器中的属性。ID生成添加到设计器的任何活动的默认标识符是基于已经存在的相似活动的数量来创建的。在添加和移除活动时,按照范围内的空槽来创建标识符。作为一个例子,第一个添加的Send活动将具有标识符“1”。第二个,“2”,依此类推。然而,如果五个Send活动已存在,开发者移除数字3(通过删除或者剪切),并且在以后重新添加另一个Send(通过复制/剪切/粘贴或通过工具箱),则标识符应该是“3”。ID的有效名字开发者可为ID提供在项目的语言中有效的名字(包括有效的转义名字)。多个活动的选择开发者经常会希望选择一组活动并且将它们移动到进度表的另一个区域。这可以按照活动等级在活动上完成,然而,开发者更有可能一次选择多个活动并将它们拖到该新区域。如果活动是相同类型的,则将启用属性浏览器以允许公共属性的集中配置。例如,如果选择的活动是ConstrainedActivityGroups,则CompletionCondition(完成条件)属性将可让开发者来配置。如果开发者选择了各种不同类型,则属性浏览器将只提供配置活动所共享的属性(例如,ID和描述)的能力。在多重选择期间,所选择的活动将在活动的角上用蓝色的指示符来装饰。这些指示符将显示为蓝色的点。具有键盘焦点的活动不以不同方式装饰。它将是一种实对空(solidversushollow)填充来表示它是处在焦点中的活动。处理程序和变量产生许多活动展示在分离代码中生成变量和/或代码处理程序的属性。执行任一动作的所有属性在属性浏览器集成中被调出用于每个活动。新变量或处理程序的创建是在开发者通过属性浏览器指定新变量或处理程序时执行的。用一个用于Send的消息变量作为例子。当指定System.String类型的“m1”时,所得到的分离代码是publicOEMessage<System.String>m1=newOEMessage<System.String>();通过为创建代码分离变量或处理程序的属性指定另一个值,创建新的变量或处理程序。现有的变量/处理程序保持完整无缺。删除所生成的变量(或者相应的处理程序)是开发者的职责。在开发者重命名分离代码中现有变量的情况下,引用它的活动不会被更新。用这个新变量更新引用原始变量的每个活动仍然是开发者的职责。当被应用于特定活动的处理程序时,跨进度表复制/粘贴和拖放操作不应用于与其相关联的处理程序。当被应用于Scope时,变量和代码处理程序的生成以略微不同的方式工作。更明确地说,所生成的变量和代码处理程序将被放置在Scope类的定义内。来自活动的作用域的所有私有的、受保护的、内部的和公用的方法和变量可在该活动上设置(只要类型和签名匹配)。来自活动的包围作用域的所有公用的和内部的方法和变量现在可合法地在该活动上设置(只要类型和签名匹配)。因此,当从菜单或者从属性浏览器创建这些变量和处理程序时,规则如下●如果变量或方法要在活动的作用域中创建,则创建为私有的。●如果变量或方法在活动包围的包围作用域中创建,则创建为公用的。上下文菜单当在一个活动上右击时,其相关联的设计器将向开发者提供活动专用动作。例如,在作用域上右击,将提供除标准的“查看代码”、剪切/复制/粘贴参数之外提供“查看作用域、查看异常、查看事件)”。这里是可基于公共性采取的可能动作的列表查看代码查看与所选择的活动相关联的代码。如果选择一个活动并且已经指定了处理程序,则选择这个选项应该将开发者带到指定的处理程序剪切从设计器移除所选择的活动并且将它复制到剪贴板。复制将所选择的活动复制到剪贴板。粘贴将最后复制的活动从剪贴板粘贴到设计器。如果没有选中选择区域,则活动将作为进度表中的活动复制。删除删除所选择的活动。属性填充并且设置焦点于所选择活动的属性浏览器。生成处理程序生成所选中活动的相应的处理程序。展开展开设计器以展示其组成部分。层叠层叠设计器以隐藏其组成部分。热链接/超链接属性浏览器集成每个活动在属性浏览器中提供上下文菜单选项作为超链接。对于所有基本活动,这包括“生成处理程序”。每个合成活动将提供“展开/层叠”和专用于该活动的菜单选项。这些在每活动等级上具体描述。活动注释配合引擎设计器使用户能够创建复杂的分层进度表。这些进度表可能非常复杂而且难以开始。注释功能给予用户注释进度表的各部分的能力,使得经注释的活动不在运行时执行。这简化了调试并且使用户能够一次监视进度表一部分的执行。活动展示一个布尔类型属性,使它能够从进度表中“伪”移除。这个活动仍存在于进度表中,然而在运行时,其存在被忽略并且它将不被执行。开发者能够通过设置在属性浏览器中展示的属性并通过上下文菜单来启用/禁用注释。注释功能具有设计时与运行时含义。用户能够在编程上注释活动,也可以使用由设计器提供的用户界面。设计器使用户能够通过选择形状和使用属性浏览器将注释属性设为真,并用橡皮圈住(rubberbanding)和多重选择活动以及在上下文菜单上选择注释菜单选项来注释形状。响应于注释,设计器将活动设计器呈现为半透明。用户有可能选择活动设计器并且在其上设置属性。XOML继续在其中具有经注释的形状;唯一的不同是注释属性被设置为真。设计时确认跳过经注释的活动并且如同活动不存在那样运作。在运行时,创作对象模型提供两个集合,它们返回活动和可执行的活动。运行时在可执行活动上起作用。附录B活动设计器IActivityDesigner(活动设计器接口)接口是由需要参加工作流的所有活动设计器实现的。这是设计器用于与其它设计器和工作流视图交谈的协议。工作流视图查找IActivityDesigner接口,以便呈现、布局或者转发事件给设计器。支持IActivityDesigner接口使所有设计器能够像窗口控件一样工作,即使设计器不是真正从窗口控件导出的。该接口还使工作流视图和如装饰服务、菜单命令服务等其它设计器基础结构能够与设计器交换信息。从IActivityDesigner导出的设计器不能有分层结构;为了具有分层结构,设计器需要实现ICompositeActivityDesigner(合成活动设计器接口)接口。下面是IActivityDesigner的定义,带有关于属性和方法的细节。表B1.IActivity设计器的属性和方法ICompositeActivityDesignerICompositeActivityDesigner是由可具有分层结构的设计器实现的;这就是它们具有子对象的原因。合成设计器负责维护本身及其所有子对象。使用ICompositeActivityDesigner接口,合成设计器分发关于其子对象的信息、提供添加和移除子设计器的功能以及启用键盘导航。下面是ICompositeActivityDesigner的定义,带有关于属性和方法的细节。表B2.ICompositeActivityDesigner的属性和方法简单设计器ActivityDesigner(活动设计器)类表示设计器最简单的实现。与工作流中的活动相关联的所有设计器是从ActivityDesigner中导出的。ActivityDesigner类从IActivityDesigner接口继承,并且为该接口提供默认的实现。工作流视图使用IActivityDesigner接口与设计器谈话。ActivityDesigner类一般由需要用于设计器绘制的非常轻量的实现的设计器继承。这些设计器没有任何子对象或者分层结构。由活动设计器提供的特征包括基于布局逻辑、呈现支持(例如,通过绘制图标、描述、边框、内部和背景)、呈现帮助文本、返回所有设计器需要的默认字形、通过DesignerVerb(设计器动词)显示上下文菜单、过滤设计时专用属性、默认事件生成、默认击中测试、触发确认、显示工具提示、以及参加键盘导航。pblicabstractclassActivityDesignerComponentDesigner,IActivityDesignerSvstem.ObjectSystem.ComponentModel.Design.ComponentDesignerSystem.Workflow.ComponentModel.Design.ActivityDesignerSystem.Workflow.ComponentModel.Design.CompositeActivityDesignerSystem.Workflow.ComponentModel.Design.CodeDesignerSystem.Workflow.ComponentModel.Design.CompensateDesignerSystem.Workflow.ComponentModel.Design.DelayDesignerSystem.Workflow.ComponentModel.Design.FaultDesignerSystem.Workflow.ComponentModel.Design.CompositeScheduleDesignerSystem.Workflow.ComponentModel.Design.InvokeWebServiceDesignerSystem.Workflow.ComponentModel.Design.BaseReceiveDesignerSystem.Workflow.ComponentModel.Design.BaseSendDesignerSystem.Workflow.ComponentModel.Design.GenericTaskDesignerSystem.Workflow.ComponentModel.Design.STSTaskDesigner合成设计器CompositeActivityDesigner是具有分层结构的设计器(例如,在它们之下具有子对象)。CompositeActivityDesigner负责管理它自己及其子对象的所有方面。它也负责与其子对象交互以转发事件。只要有修改CompositeActivityDesigner所包含的活动设计器集合的请求;它就传递一个上下文(ContextBase(上下文基)),该上下文指定一个位置,需要将活动从这个位置移除。ContextBase可由每个CompositeActivityDesigner导出类专门化,以指定专用于它们的上下文。它的例子是SequentialActivityDesigner(顺序活动设计器),通过从ContextBase导出一个称为ConnectorContext(连接器上下文)的类来专门化ContextBase。CompositeActivityDesigner从ICompositeActivityDesigner接口导出,并且为它提供默认的实现。由CompositeActivityDesigner提供的特征包括展开层折叠设计器、拖放指示符、布局本身和子对象、绘制本身和子对象、子对象的击中测试、以及从分层结构插入移除活动。publicabstractclassCompositeActivityDesignerActivityDesigner,ICompositeActivityDesignerSystem.ObjectSystem.ComponentModel.Design.ComponentDesignerSystem.Workflow.ComponentModel.Design.ActivityDesignerSystem.Workflow.ComponentModel.Design.CompositeActivityDesignerSystem.Workflow.ComponentModel.Design.SequentialActivityDesignerSystem.Workflow.ComponentModel.Design.ParallelActivityDesignerSystem.Workflow.ComponentModel.Design.ConstrainedActivityDesignerCompositeActivityDesigner是抽象类并且不能被实例化,因为它不能在其自身上存在。顺序、并行和CA设计器都是这个类的专门化。SequentialActivityDesigner(顺序活动设计器)SequentialActivityDesigner类表示在其下具有子对象且所有子对象是顺序排序的所有设计器。子对象通过称为连接器的链接来连接,连接器还用于修改子对象的顺序。SequentialActivityDesigner类是CompositeActivityDesigner的专门化,并且提供下列特征集连接器开始和结束位图绘制、顺序地布局所有子对象并且更新链接它们的所有连接器、在子对象之间绘制连接器、在拖放发生时高亮放置区域、击中测试连接器、使用上下箭头键的顺序键盘导航、以及为连接器返回字形。internalabstractclassSequentialActivityDesignerCompositeActivityDesignerSystem.ObiectSystem.ComponentModel.Design.ComponentDesignerSystem.Workflow.ComponentModel.Design.ActivityDesignerSystem.Workflow.ComponentModel.Design.CompositeActivityDesignerSystem.Workflow.ComponentModel.Design.SequentialActivityDesignerSystem.Workflow.........Design.ActivityPreviewDesignerSystem.Workflow.........Design.CompensationHandlerDesignerSystem.Workflow.........Design.ConditionedDesignerSystem.Workflow.........Design.EventHandlerDesignerSystem.Workflow.........Design.ExceptionHandlerDesignerSystem.Workflow.........Design.ScopeDesgnerSystem.Workflow.........Design.SequenceDesignerSystem.Workflow.........Design.WhileDesigner所有上述设计器是SequentialActivityDesigner的专门化;它们全部主要在绘制方面不同。所有这些设计器具有一种特殊的方法以在工作流上表示它们自己,但它们全部消除了由SequentialActivityDesigner提供的共同功能。ParallelActivityDesigner(并行活动设计器)ParallelActivityDesigner是CompositeActivityDesigner的另一个专门化,它包含多个SequentialActivityDesigner。这些SequentialActivityDesigner的每一个是并行设计器中的一个分支。并行设计器提供下列专门化的特征布局多个顺序设计器、拖放用于添加附加的分支的指示符、使左右箭头键在并行分支之间遍历的键盘导航、以及绘制连接器以链接多个并行分支。internalabstractclassParallelActivityDesignerCompositeActivityDesigner\System.ObjectSystem.ComponentModdel.Design.ComponentDesignerSystem.Workflow.ComponentModel.Design.ActivityDesignerSystem.Workflow.ComponentModel.Design.CompositeActivityDesignerSystem.Workflow.ComponentModel.Design.ParallelActivityDesignerSystem.Workflow.........ConditionalDesignerSystem.Workflow.........ListenDesignerSystem.Workflow.........ParallelDesignerConditional、Listen和Parrallel设计器是ParallelActivityDesigner的专门化,具有与它们相关联的附加绘制逻辑。ActivityPreviewDesigner(活动预览设计器)ActivityPreviewDesigner是顺序设计器,但具有以集合袋(collectionbag)形式显示多个设计器的集合的能力。ActivityPreviewDesigner使用幻灯片的比喻来显示这个集合。当一个特定的设计器被选中时,其表示在活动预览设计器所主宿的预览窗口中显示。ActivityPreviewDesigner具有两种模式编辑模式和预览模式。在预览模式中,用户不能修改已选中的设计器。该模式使用户能够看见设计器的整个表示而不必滚动。编辑模式允许设计器被修改。由ActivityPreviewDesigner提供的特征包括预览条带以显示活动的集合、预览当前选中的活动、以及编辑所选中的设计器的能力。internalabstractclassActivityPreviewDesignerSequentialActivityDesignerSystem.ObjectSystem.ComponentModel.Design.ComponentDesignerSystem.Workflow.ComponentModel.Design.ActivityDesignerSystem.Workflow.ComponentModel.Design.CompositeActivityDesignerSystem.Workflow.ComponentModel.Design.SequentialActivityDesignerSystem.Workflow.........Design.ActivityPreviewDesignerSystem.Workflow.........Design.GenericCollectionDesignerSystem.Workflow.........Design.CAGDesignerScope(作用域)和Service(服务)设计器Scope和Service设计器是特殊的设计器。其每一个可具有与它们相关联的异常、事件和补偿。Scope和Service在用户代码文件中还具有与它们相关联的类,并且用户具有将变量限制在这些类中的能力。Scope和Service设计器被示出为不同与其它设计器,并且显示水印和通过绘制阴影来高亮它们。Scope和Service设计器具有改变视图的能力,因此用户可翻转视图来揭示与它们相关联的异常、事件和补偿。当用户在Service或Scope图标上悬停时,出现一个下拉选项板,它使用户能够选取异常、事件或补偿视图之一。设计器视图随后被翻转,并且显示包含在所选中的视图中的活动。用户可在任何时间点只查看属于任何一个视图的活动。视图的翻转是通过过滤包含在Scope或者Schedule中的子活动来完成的。Scope和Schedule可具有ExceptionHandler、EventHandlers和Compensate中的最多一个作为它的子对象。基于用户观看的视图;设计器过滤掉这些子对象,以只显示可出现在所选中的视图中的子活动;因而实现支持多视图的效果。Schedule设计器通常被设置为工作流视图中的根设计器。internalclassScopeDesignerSequentialActivityDesignerinternalclassServiceDesignerScopeDesignerSystem.ObjectSystem.ComponentModel.Design.ComponentDesignerSystem.Workflow.ComponentModel.Design.ActivityDesignerSystem.Workflow.ComponentModel.Design.CompositeActivityDesignerSystem.Workflow.ComponentModel.Design.SequentialActivityDesignerSystem.Workflow.........Design.ScopeDesignerSystem.Workflow.........Design.ServiceDesignerServiceRootDesigner(服务根设计器)ServiceRootDesigner与由设计器宿主所包含的根组件相关联。它负责创建随后要主宿在设计器窗口窗格中的工作流视图。ServiceRootDesigner还支持IToolBoxUser(工具箱用户接口)接口,它给予通过在工具箱项上双击来添加工具箱项的能力。Design-timeDescriptors(设计时描述符)创作对象模型中的每个活动具有描述其在设计时期间行为的元数据。这包括关联活动(设计器)以及属性网格行为(命名、描述、过滤、属性编辑器等)。类型\属性\事件设计时行为是使用零个或多个下列元属性来描述的-SRCategoryAttribute(SR类别元属性)-配合引擎元属性。提供本地化的类别名。-SRDescriptionAttribute(SR描述元属性)-配合引擎元属性。提供本地化的描述。-EditorAttribute(编辑器元属性)-提供UITypeEditor(UI类型编辑器)-TypeConverter(类型转换器)-提供过滤、值列表以及类型之间的转换。-BrowsableAtrribute(可浏览属性)-在设计时显示/隐藏成员。SRCategory(SR类别)和SRDescription(SR描述)只是资源名字与串之间的映射。大多数编辑器(UITypeEditor)是用于处理对话框(像CorrelationSetsDialog(相关集对话框))或者下拉列表的管理器。PropertyDescriptor(属性描述符)处理设计时的属性,并且由默认的TypeConverter、自定义的TypeConverter(它是如上被声明为元属性的)或者TypeDescriptor(类型描述符)中任一个来向其传递属性。UI类型编辑器为配合引擎组件模型中的各属性提供编辑器。属性浏览器使用它们显示省略号或者下拉并且用于起动编辑器。TypeConverters(类型转换器)类型转换器提供将对象转换到其它类型/从其它类型转换到对象的方法、提供表示设计时的对象属性的PropertyDescriptor列表、并且可能提供要属性网格的属性下拉中使用的值。下面是在配合引擎组件模型中实现的某些TypeConverter-DeclTypeConverter(声明类型转换器)基类到所有活动的类型转换器。实现CanConvertFrom()、CanConvertTo()、ConvertFrom()、ConvertTo(),它们将活动对象转换成串/从串转换成活动对象(以显示属性网格中活动的名字,并且允许名字编辑以创建活动)。而且,GetSite()提供对服务的访问。-HandlerDeclTypeConverter(处理程序声明类型转换器)事件的类型转换器。从DeclTypeConverter导出。实现GetStandardValues(),它使用IEventBindingService(事件绑定服务接口)来显示兼容的处理程序。-VariableDeclTypeConverter(变量声明类型转换器)变量(消息、通道、相关等)的类型转换器。从DeclTypeConverter导出。实现GetStandardValues(),它使用IFieldBindingService(字段绑定服务接口)来显示兼容的变量字段。另外,类型转换器过滤掉“Name(名字)”属性,并且为表现为类属类型的类型属性设置一个特殊的属性描述符。属性描述符属性描述符为活动对象提供设计时服务。它提供名字、描述、类别、类型转换器信息,并在获得/设置属性时提供附加功能。默认地,TypeConverter将为所有属性提供PropertyDescriptor。然而,TypeConverter可移除、添加或者包装它们以提供类型的不同设计时行为。下面是创作对象模型中实现的某些PropertyDescriptor-DynamicPropertyDescriptor(动态属性描述符)创作对象模型中所有属性描述符的基类。实现默认属性描述符的包装器,并且将所有方法委托给它。另外,提供直接从对象(如果它是组件)或者通过IReferenceService(引用服务接口)对于对象站点的访问。-VariableDeclPropertyDescriptor(变量声明属性描述符)所有变量(消息、通道、相关等)的属性描述符。重载SetValue()以提供如下的代码分离字段-获得要设置的变量及其站点。-获得包含作用域的站点。-获得包含作用域的IEventBindingService。注意,每个作用域具有它自己的IEventBindingService以及它自己的字段集。-用服务确认字段名。-打开设计器事务。-保存值。-调用IFieldBindingService.CreateField(),将该字段添加到代码分离文件。-提交事务。-HandlerDeclPropertyDescriptor(处理程序声明属性描述符)所有处理程序的属性描述符。重载SetValue()以提供如下的代码分离字段-获得要设置的HandlerDeclaration(处理程序声明)对象及其站点。-获得IEventBindingService。-打开设计器事务。-创建LocalEventDescriptor(本地事件描述符)。-获得事件的PropertyDescriptor(使用eventBindingService.GetEventProperty())并且在其上设置HandlerDeclaration。-设置HandlerDeclaration对象的“Name(名字)”属性。-提交事务。-ArrayElementPropertyDescriptor(数组元素属性描述符)表示集合中一个项的属性描述符。由于-例如相关集等集合项没有属性描述符(它们不是属性),因此ArrayElementPropertyDescriptor伪造描述符,如同它们是属性一样,因而允许在属性浏览器内显示它们。这个属性描述符被设计成由任何上述属性描述符来包装。-LocalEventDescriptor(本地事件描述符)用于表示HandlerDeclaration的EventDescriptor(事件描述符)。创作对象模型中的处理程序不是真的事件,而是属性,因此引入自己的EventDescriptor用于要使用的IEventBindingService。使用ICustomTypeDescriptor(自定义类型描述符接口)ICustomTypeDescriptor是设置组件描述符的另一种方法。组件本身实现该接口并且提供描述符,如类型转换器、默认值等等。GenericActivity(类属活动)、InvokeWebServiceActivity调用web服务活动)和InvokeSchedule(调用进度表)实现这个接口。使用IExtenderProvider(扩展器供应者接口)这是向组件引入设计时属性的又一种技术。扩展类RulePropertyProviderExtender(规则属性供应者扩展器)向ServiceDesigner(服务设计器)提供规则属性。通过经由ProvidePropertyAttribute(提供属性元属性)装饰扩展器类、实现元属性的取值器和置值器、以及将扩展器类添加到可通过组件的站点(Schedule.Site)访问的IExtenderProviderService(扩展器供应者服务接口)类(在此例中,由RulePropertyProviderExtender实现)来添加属性。可扩展性支持System.Workflow.ComponentModel.Design名字空间为用户提供各种可重用的类,以在创建它们自己的活动设计器并且将它们插入到配合引擎设计器之中时使用。下面是用户可使用的类的列表。-ActivityDesigner(活动设计器)ActivityDesigner给予用户添加在其下没有其它活动的分层结构的简单活动的能力。用户需要从这个设计器继承并且可定制位图、描述和绘制。-SequentialActivityDesigner(顺序活动设计器)SequentialActivityDesigner使用户能够编写可在其中包含多个活动的设计器。所有这些活动被顺序地排列,并且使用连接器线来链接。用户可从这个类导出,并且提供自定义的着色、描述、图标等。-ParallelActivityDesigner(并行活动设计器)ParallelActivityDesigner使用户能够编写可在其中具有多个合成活动并且以并行方式排列它们的活动设计器。该类还使用户能够定制描述、图标、颜色等。该类可通过继承来扩展。-OrchestrationEngineToolboxItem(配合引擎工具箱项)OrchestrationEngineToolboxItem使用户能够创建自定义的工具箱项。该类给予用户控制序列化的能力。该类提供挂钩,使用挂钩,用户可在活动被添加到设计器中时弹出自定义的UI。用户可通过继承重用该类。用户需要通过使用ToolBoxItem(工具箱项)元属性来提供工具箱项。-TypeBrowserEditor(类型浏览器编辑器)TypeBrowserEditor使用户能够浏览设计器中可用的类型。该类是通过将它与类型为System.Type的属性相关联来使用的。用户使用UITypeEditor(UI类型编辑器)元属性来将该类与属性相关联。-TypeConverter(类型转换器)类配合引擎组件模型提供各种类型转换器,它们使用户能够定义他们自己的类型转换器。通过继承来扩展类型转换器,可使用所有类型转换器。-DesignerGlyph(设计器字形)DesignerGlyph类可由用户用于在设计器之上绘制自定义的字形。用户可能想要显示需要在Z顺序的最顶上绘制的某些可视字形。DesignerGlyph类可用于绘制这类字形。可通过继承扩展这个类来使用它。-DesignerAction(设计器动作)用户可将DesignerAction与DesignerGlyph相关联。当用户在DesignerGlyph上点击时显示这些动作。自定义的设计器动作可通过从DesignerAction类继承来创建。附录C活动的语义确认这些示例性确认检查对于由配合引擎开发的多个活动是共同的。所有活动-活动的ID属性必须是项目语言(C#或VB)中有效的标识符。-非Scope活动在包含作用域内必须是唯一的。Scope活动的ID跨所有Scope必须是唯一的。-为变量的任何属性必须被设置成可见的变量-例如,它在活动的Scope中或者在包含作用域中定义,并且必须是公用的。代码分离处理程序-活动的ID属性必须是项目语言(C#或VB)中有效的标识符。-处理程序必须存在于包含该处理程序的活动的代码分离作用域类中,并且必须具有匹配的方法签名。消息-OEMessage<T>的参数类型T必须是可序列化的。相关-OECorrelation<T>的参数类型T必须实现IComparable(可比较接口)。规则-规则的处理程序必须传递处理程序确认。处理程序的签名是由规则的类型定义的。活动专用的确认检查这些示例性确认检查对于一个活动类型是专用的。Code-UserCodeHandler(用户代码处理程序)属性必须被指定,并且必须具有签名voidMethod()。Compensate-Compensate活动只可出现在ExceptionHandler活动或者TransactionType(事务类型)不是None(无)的作用域的Compensate活动内。-如果CompensateScope(补偿作用域)为True(真),则Scope属性必须被设置为Scope活动,它或者是发出Compensate的Scope的直接子对象,或者是其本身。-如果CompensateScope为False(假),则Invoke属性必须被设置为CompositeSchedule活动,它是发出Compensate的Scope的直接子对象。Conditional-Conditional活动必须具有至少一个子对象。-只有ConditionalBranch活动允许作为子对象。ConditionalBranch-父活动必须是Conditional。-除非ConditionalBranch是其父活动的最后一个子对象,否则必须指定Rule属性。ConstrainedActivityGroup-CompletionRule(完成规则)属性必须被设置为有效的规则。-只有Constrained的活动允许作为子对象。Constrained-父活动必须是ConstrainedActivityGroup。-Constrained必须有且只有一个子对象。-如果指定了DisableRule和EnableRules,则它们必须是有效的。Delay-TimeoutProvider(超时供应者)属性必须被设置为有效的处理程序。EventHandlers-父对象必须是Scope活动。-只有EventDriven活动允许作为子对象。-如果任何子EventDriven活动的第一个子对象是其Activation(激活)被设置为True的Receive,则所有子EventDriven都必须像第一个子对象一样具有其Activation被设置为True的Receive。-只有一个子EventDriven活动可具有Delay活动作为它的第一个子对象。EventDriven-父对象必须是Listen活动或EventHandlers活动。-第一个子对象必须或者是Delay或者Receive活动。-至少一个子活动必须存在。Fault-ExeceptionProvider属性必须设置为具有签名System.ExceptionMethod()的有效处理程序。-Fault活动不能嵌套在TransactionType设置为Atomic(原子)的Scope活动内。InvokeSchedule-被启用者的类型必须从InvokeSchedule导出,并且必须具有默认的构造函数。-被调用者的任何具有InAttribute(输入元属性)、OutAttribute(输出元属性)或者OptionalAttribute(可任选元属性)的公用属性可被分配可分配类型的可见变量。-如果ExecutionMethod(执行方法)属性设置为Exec(执行),则具有OutAttribute但没有InAttribute的属性不能分配给它。-如果ExecutionMethod属性设置为Exec,则变量必须是可序列化的。-Channel(通道)或Correlation(相关)不能被分配给具有OutAttribute的属性。-不允许递归调用。InvokeWebService-ProxyClassName(代理类名)属性必须被设置为有效的代理类。-MethodName(方法名)属性必须被设置为代理类中的web方法。-web方法的所有参数必须被指定并且可见,而且其类型必须是可分配的。此外,对于任何输出/引用参数和返回值,指定的参数不能是只读的。Listen-只有EventDriven活动允许作为子对象。-至少两个子对象必须存在。-如果任何子EventDriven活动的第一个子对象是其Activation被设置为True的Receive,则所有子EventDriven活动必须与第一个子对象一样具有其Activation被设置为True的EventDriven活动或者Delay活动。-只有一个子EventDriven活动可具有Delay活动作为其第一个子对象。Parallel-只有Sequence活动允许作为子对象。-至少两个子对象必须存在。-如果任何子Sequence活动的第一个子对象具有其Activation被设置为True的Receive,则所有子Sequence活动的必须与第一个子对象一样具有其Activation被设置为True的Receive。Receive(接收)-Message(消息)属性必须被设置且有效。-如果HasTypedChannel(具有类型化的通道)属性为True,则TypedChannel(类型化通道)属性必须被设置且有效-类型OEInboundChannel<T>的可见变量,其中T是接口。-如果HasTypedChannel属性为True,则TypedChannel的Operation(操作)必须是来自具有签名voidMethod(Type参数)的接口的方法。-如果HasTypedChannel属性为True,则Message的Type(类型)必须是可从Operation参数的Type分配的。-如果HasTypedChannel属性为False,则UntypedChannel(非类型化通道)属性必须被设置且有效-类型InboundChannel(入站通道)的可见变量。-如果Activation属性是True,则Receive必须是Schedule中第一个可执行语句,并且只可具有Sequence、Parallel、EventDriven、Listen、Scope或Schedule活动作为祖先对象。-如果Activation属性是True,则Schedule必须不将CompileAs(编译为)属性设为Activity(活动)。-如果Activation属性是True,则Receive必须不在Compensation或ExceptionHandler或While活动内嵌套。-如果Activation属性是False,则Receive必须遵循至少一个Correlation。-Correlation最多可被指定一次,并且不能同时被初始化并被遵循。-如果设置OnAfterReceive(在接收之后)处理程序,则它必须具有签名voidMethod()。ReceiveRequest-TypedChannel属性的Operation(如果需要设置)必须具有签名ReturnTypeMethod(Type参数)。ReceiveResponse-TypedChannel属性的Operation(如果需要设置)必须具有签名ReturnTypeMethod(Type参数)。-Operation的ReturnType(返回类型)必须可从Message的Type分配。-SendRequest属性必须有效的SendRequest活动的合格名字。-SendRequest活动必须在ReceiveResponse之前发生。-SendRequest和ReceiveResponse活动必须不在同一原子作用域内嵌套。-ReceiveResponse活动不能遵循Correlation。Send-Message属性必须被设置且有效。-如果HasTypedChannel属性为True,则TypedChannel属性必须被设置且有效-类型OEOutboundChannel<T>的可见变量,其中T是接口。-如果HasTypedChannel属性为True,则TypedChannel的Operation必须是来自具有签名voidMethod(Type参数)的接口的方法。-如果HasTypedChannel属性为True,则Operation参数的Type必须是可从Message的Type分配的。-如果HasTypedChannel属性为False,则UntypedChannel属性必须被设置且有效-OutboundChannel(出站通道)类型的可见变量。-Correlation最多可被指定一次,并且不能同时被初始化并被遵循。-如果设置OnBeforeSend(在发送之前)处理程序,则它必须具有签名voidMethod()。SendRequest-TypedChannel属性的Operation(如果需要设置)必须具有签名ReturnTypeMethod(Type参数)。SendResponse-TypedChannel属性的Operation(如果需要设置)必须具有签名ReturnTypeMethod(Type参数)。-Operation的ReturnType必须是可从Message的Type分配的。-ReceiveRequest属性必须是有效的ReceiveRequest活动的合格名字。-ReceiveRequest活动必须在SendResponse之前发生。-SendResponseActivity不能遵循Correlation。Scope-其Synchronize(同步化)被设置为True的Scope不能在其Synchronize被设置为True的另一Scope内嵌套。-TransactionType为Atomic的Scope不能在ExceptionHandler活动内嵌套。-TransactionType为Atomic或LongRunning的Scope必须在TransactionType为LongRunning的Scope内嵌套(除非Scope是Schedule)。-如果TransactionType是Atomic,则Synchronized属性必须是True。-如果TransactionType是LongRunning,则TimeoutProvider处理程序必须设置为具有签名System.DateTimeMethod()。Schedule-分离代码类必须有且只有一个构造函数。Sequence没有确认。Suspend-Suspend活动不能在TransactionType被设置为Atomic的Scope内嵌套。-ErrorString(错误串)属性必须是有效的串。Terminate-ErrorString属性必须是有效的串。While-ConditionalRule(条件规则)属性必须是有效的规则。相关集和护卫确认检查这些示例性确认检查对于相关集和护卫情况是专用的。-Correlation必须在它被遵循之前被初始化。-Correlation可用某些异常至少初始化一次。-初始化相关的Send和遵循它的Receive驻留在同一个原子作用域中。-顺序护卫的检测。-并行护卫的检测和确认○并行护卫中的所有Receive活动必须初始化同一组Correlation。○并行护卫中的所有非激活Receive活动必须遵循同一组Correlation。○在Parallel中的激活Receive必须初始化Correlation。如果激活Receive是工作流中第一个可执行的非合成活动(例如,忽略Scope、Parallel、Listen等),并且它的祖先对象是Parallel或Listen,则Parallel或Listen的所有分支必须具有激活Receive作为它的第一个可执行活动。附录D示例性名字空间APISystem.Workflow.ComponentModel名字空间包含标准工作流活动的实现。Activity(活动)对象模型提供API来创作配合程序。另外,在声明对象模型中的每个对象具有继承性,它使得将设计时行为与组件相关联成为可能。下面是表示使用声明对象模型接收消息并发送它的配合程序的例子。serviceService1{messagemsg1;portport1;portport2;receive(port1,msg1);send(port2,msg1);}构造这样一个服务的相应创作API包括  //用名字″Service1″声明一个服务。  Scheduelschedule=newSchedule(“Service1”);  schedule.TransactionType=TransactionType.Atomic;  //用名字″receive1″声明接收,并且它使用端口″port1″和消息″msg1″  Receivereceive1=newReceive(“receive1”);  receive1.Port=“port1”;  receive1.Message=“msg1”;  schedule.AddActivity(receive1);  //用名字″send1″声明发送,并且它使用端口″port2″和消息″msg1″  Sendsend1=newSend(“send1”);  send1.Port=“port2”;  send1.Message=“msg1”;  schedule.AddActivity(send1);  //向服务声明给出外部用户代码  serviceDeclaration.ExtemalUserCode=″<someexternalusercode,inwhichuser  hasdeclared‘port1’,‘port2’and‘msg1’variables.>″;下表简要地描述该名字空间的描述和用途。表B1.System.Workflow.ComponentModel名字空间模型工作流组件模型是分层的声明组件模型。对象模型的根是进度表。该对象模型既由工具编写者使用,又由运行时执行使用。组件模型中的每个活动由IActivity(活动接口)接口表示。IActivity接口从IComponent(组件接口)继承。IComponent具有允许活动在设计时通信的Site(站点)属性。该组件模型可由第三方活动编写者扩展。活动分类如下1)基本活动基本活动没有子活动,并且它包括属性的平面列表。2)合成活动合成活动从基本活动继承,并且保存子活动的列表。除了上述基本和合成活动分类之外,Scope和Schedule活动被不同地对待。Scope和Schedule具有与它们相关联的对应用户代码类。连同所有的活动,该名字空间还提供下列特征序列化到xoml文件/从xoml文件反序列化、Schedule活动的编译、以及每个活动上的确认实现。IActivity接口从IComponent继承  publicinterfaceIActivityIComponent  {  //这是其父作用域内的活动的唯一标识符。  //跨作用域,这个id可具有重复的值。为跨作用域标识活动  //必须使用合格的名字。而且对于Scope和Schedule,该  //属性告诉它们一起工作的用户代码类的名字。  stringID{get;set;}<!--SIPO<DPn="68">--><dpn="d68"/>  //该属性返回活动的合格ID。活动的合格ID是用“.”和活动ID组合成的  ParentScopeID。  stringQualifiedID{get;}  //这是取值、置值属性,用于保持关于过程中活动的描述。  StringDescription{get;set;}  //这是取值、置值属性,用于注释或者去注释活动。  //如果活动被注释,则它不参加执行和确认检查。  boolCommented{get;set;}  //这是取值属性,它告诉活动是否要为运行时模式实例化。  //通常当活动图为运行时模式实例化时,活动使它们的所有属性只读,  //因此用户将不能改变它们。  boolIsRuntimeMode{get;}  //该方法返回活动在运行时间的状态。因为多个配合实例共享同一活动树,  //所以该方法基于将为该特定活动和接口返回IActivityState(活动状态接口)  //接口,采用指向配合实例的指针。IActivityState接口提供一种方法,  //来取得Status(状态)和Outcome(结果)属性。  IActivityStateGetState(objectscopeBoundObject);  //该属性的目的是允许在编程上将某一自定义数据与活动相关联。  //这用于编程而不是活动DOM。  IDictionaryUserData{get;}  //该属性告知该活动的父活动。  ICompositeActivityParent{get;set;}  //该属性告知该活动的父作用域。该属性走查所有父对象,  //直到取得一个作用域。还要注意,作用域的父作用域只返回该父作用域。  IScopeParentScope{get;}  //该函数用于确认活动。在上下文中以IServiceProvider的形式传递该函数,  //从该接口,活动编写者可取得不同的服务来确认活动的内容。目前该函数  //是从Xoml编译器以及设计器调用。  //两个服务包括1)ITypeProvider(类型供应者接口)  //2)IEnvironmentService(环境服务接口)。  IValidationError[]Validate(IServiceProvidercontext);<!--SIPO<DPn="69">--><dpn="d69"/>  }下面是IValidationError(确认错误接口)的定义。该错误是在调用活动上的Validate(确认)时返回的。publicinterfaceIValidationError{//错误文本返回错误的描述。stringErrorText{get;}//该属性的目的是允许在编程上将某一自定义数据与错误相关联。//例如,该属性中的‘typeof(string)’关键字应该保存属性的名字。IDictionaryUserData{get;}}每个合成活动从ICompositeActivity(合成活动接口)继承。与基本活动相比,合成活动具有附加的属性“Activities(活动)”和ExecutableActivities(可执行活动)。下面是ICompositeActivity的接口定义。  publicinterfaceICompositeActivityIActivity  {  //该属性用于取所有子活动。请注意,它返回活动的IItemList  //(项列表接口)而非活动的IList(列表接口)。  //IItemList是在活动DOM中定义的接口,它具有一个额外的事件,  //以在从列表添加或者移除活动时通知。  IActivityCollectionActivities{get;}  //可执行活动返回非注释的活动的集合。  //该属性只返回活动的只读集合。如果用户想要改变、添加或者删除  //活动,则应该使用“活动”集合。  IList<IActivity>ExecutableActivities{get;}  }IActivityCollection(活动集合接口)从IList继承,它具有一个关于对列表的修改的附加时间,以及与在运行时模式中对集合动态更新有关的多个方法的耦合。  publicinterfaceIActivityCollection<T>IList<T>  {  //当从该列表添加、移除或替换某一项时激发的唯一事件。<!--SIPO<DPn="70">--><dpn="d70"/>  eventItemListChangeHandler<T>ListChanged;  //索引器属性,用于基于活动的ID属性取活动。  IActivitythis[stringkey]{get;}  //动态地在运行时改变活动集合的方法。这些方法采用指向  //ScopeBoundObject(作用域边界对象)(向其应用修改的实例)的指针。  //添加活动  voidAdd(objectscope,IActivityactivity);  //添加活动范围  voidAddRange(objectscope,ICollection<IActivity>activities);  //移除活动  voidRemove(objectscope,IActivityactivity);  //替换活动  voidReplace(objectscope,IActivityreplaceThis,IActivitywithThis);  }运行时值供应者活动属性的值是常数或者指向代码分离文件中的变量或方法的指针。例如,Send活动上的Message属性指向代码分离文件中的成员变量,Terminate活动的ErrorString属性也可能想要以文字形式保存实际的串,或者它可能想要指向代码分离文件中的变量。从运行时观点来看,它只关心取得属性的值,这或者可以是从其检索值的文字形式,或者是代码分离文件中的变量。publicabstractclassRuntimeValueProvider{//该属性取得该对象将返回的值的类型。TypeRuntimeType{get;}//该方法用于在运行时检索属性的值。objectGetValue(objectscopeBoundObject);}在一个实施例中,有两种不同类型的值供应者,1)文字声明2)成员声明。成员声明这些对象表示特定运行时类型的用户代码文件中的变量。例如,Send上的Message属性指向用户代码分离文件中的变量,它必须是“System.Workflow.Runtime.OEMessage<T>”类型。这一属性是‘string’类型的,并且它的值是变量的名字。除了串值外,非活动类具有与它们相关联的某些元数据。例如,这些可告知这些变量应该引用什么运行时类型等。  publicclassMemberDeclaration  {  //名字属性指向代码分离文件中的成员变量或方法。  //名字可以是受作用域限制的。  stringName{get;set;}  //该属性存储代码分离文件中的变量或处理程序声明的类型。  TypeRuntimeType{get;set;}  //该属性只取运行时的值,它只在该类的对象在为运行时模式实例化时取值。  ScopeScope{get;}  //该属性告知对象是否已经为运行时使用而被实例化。  boolIsRuntimeMode{get;}  //该确认方法确认该对象并返回确认错误的集合。  //它传入该对象是其一部分的活动和父属性的名字。  IValidationError[]Validate(IServiceProviderserviceProvider,IActivityactivity,  stringparentPropName);  }从MemberDeclaration(成员声明有两个主要的继承分支1)VariableDeclaration(变量声明2)HandlerDeclaration(处理程序声明。VariableDeclaration用于引用用户代码分离文件中的变量,而HandlerDeclaration用于引用用户代码分离文件中的方法。VariableDeclWithOneArg(具有一个变元的变量声明)从variableDecl(变量声明)继承,并且用于引用用户代码分离文件中的变量,其运行时类型是具有一个变元的类属类型。还有许多与这些声明类相关联的设计时功能。例如,使用VariableDeclaration作为活动的属性类型自动地在属性浏览器窗口中给出一个组合框,以列出特定运行时类型的代码分离文件中的所有变量。这些类还具有进行语义检查的功能。例如,HandlerDeclaration检查方法名字是否有效、该方法是否存在于用户代码文件中、以及该方法的签名是否匹配由运行时类型属性所标识的类型。变量声明VariableDeclaration从MemberDeclaration继承,并且在代码分离文件中存储变量的名字。它在运行时模式具有三个附加的方法  publicclassVariableDeclarationMemberDeclaration  {  ...  //FieldInfo(字段信息)对象,在运行时指向代码分离文件中的变量。  publicFieldInfoFieldInfo{get;}  //取进度表的特定实例的变量在运行时的值的方法  publicobjectGetRuntimeValue(objectscopeObj);  //设置进度表的特定实例的变量在运行时的值的方法  publicvoidSetRuntimeValue(objectscopeObj,objectvalue);  }TypedVariableDeclaration(类型化变量声明)从VariableDeclaration继承,并且使运行时类型属性为只读。处理程序声明HandlerDeclaration从MemberDeclaration继承,并且指向代码分离文件中方法名字。它具有一个运行时的附加方法,并且返回将指向代码分离文件类中方法的委托对象。TypedVariableDeclaration从HandlerDeclaration继承,并且它使运行时类型属性为只读。文字声明LiteralDeclaration(文字声明)对象包含文字值,而不是指向代码分离文件中的变量。下面是该类的定义。publicclassLiteralDeclarationRuntimeValueProvider{//该属性用于取或设置文字值。stringLiteralValue{get;set;}}规则声明在商业过程中使用规则以动态地改变配合的行为。工作流组件模型定义插入任意规则技术的方法。为实现自定义规则技术,必须定义从RuleDeclaration(规则声明)继承的类。它具有一个抽象方法来确认规则并且向继承的类通知运行时初始化模式。自定义规则技术供应者从RuleDeclaration类继承并且覆盖这些方法。它还提供用于定义规则定义的附加属性。当前的工作流组件模型具有两个RuleDeclaration类,一个是基于代码的规则声明,它具有与其相关联的布尔类型处理程序方法来对规则求值并且返回真或假值。另一种技术是基于BRE的规则声明,它提供一个对象模型来定义规则。规则声明类的运行时对应对象是RuleEvaluator(规则求值器)。工作流引擎查找RuleDeclaration类上的RuleEvaluator元属性。该元属性告知实现IRuleEvaluator(规则求值器接口)接口的Type(类型)的名字。IRuleEvaluator接口只有一个返回布尔类型值的方法Evaluate()。运行时模式用于在设计时创作配合程序的同一活动图也在运行时被实例化。在运行时,工作流引擎调用活动图的根对象以执行其本身,该根对象进而调用其子活动以执行它们本身,依此类推,作为合成活动的子活动上请求其子活动执行它们本身。当活动图为运行时使用而被实例化时,活动不允许改变它们的属性。活动可通过覆盖OnRuntimeInitialized()方法来了解有关运行时初始化的情况,该方法是在Activity(活动)类中定义的受保护方法。活动可在该方法上进行自定义的运行时专用初始化。通常在活动的运行时实例化时,它们将其用串表示的信息解析成实际的运行时类型信息。例如,InvokeWebService活动在设计时用串形式保存代理类的名字,当为运行时而实例化InvokeWebService时,它将代理类名解析成实际的System.Type对象。工作流引擎只为正在运行的配合的多个实例保存一个活动图。活动上的GetState(objectscopeBoundObject)方法返回配合的一个特定实例的IActivityState。使用IActivityState接口可取得活动的Status和Outcome属性。  publicinterfaceIActivityState  {  //取活动的状态。在运行时执行模式,活动经历多个状态转移,  //例如,已启用、已执行、已完成、已关闭、已取消。  //状态属性告知活动的准确的当前状态。  StatusStatus{get;}  //工作流引擎保存活动的执行的Outcome。如果活动执行得到取消,则  //Outcome将被取消,如果活动执行抛出异常,则Outcome将是  //Failed(已失败),否则如果活动没有完成且关闭,则Outcome将是  //Succeeded(已成功)。  OutcomeOutcome{get;}  }与活动的运行时实例化并行,非活动声明也为运行时模式实例化。例如,其名字为“art”且运行时类型为“System.String”的VariableDeclaration将在运行时实例化时具有System.Reflection.FieldInfo对象,它将指向代码分离文件中的“Art”变量。类型为VariableDeclaration或者HandlerDeclaration的活动的属性也可覆盖OnRuntimeInitialized(),以得到关于运行时模式的通知。MemberDeclaration上的‘Scope’属性将用Member(成员)所属的Scope来初始化。同样,VariableDeclaration和HandlerDeclaration上的GetRuntimeValue()和SetRuntimeValue()方法开始返回进度表的一个特定实例的变量或方法的值。编写自定义活动为编写自定义活动,活动类或者从ActivityDecl(活动声明)或者从CompositeActivityDecl(合成活动声明)继承。为支持活动的自定义序列化,已向活动类添加了SerializerAttribute(序列化器元属性)。设计器元属性将设计器与活动相关联。这里是一个示例活动代码  [ToolboxItem(typeof(WorkflowToolboxItem))]  [Designer(typeof(FooActivityDesigner),typeof(IDesigner))]  [ActivityExecutor(typeof(FooExecutor))]  publicsealedclassFooActivityActivity  {<!--SIPO<DPn="75">--><dpn="d75"/>  publicFooActivity()  {  }  privatestringfoo=string.Empty;  publicstringFoo  {  get  {  returnthis.foo;  }  set  {  this.foo=value;  }  }  }使用组件模型的示例程序下面是一个针对组件模型编程的示例代码。Schedule是对象模型的根。这个例子创建一个新的Schedule枚举类型,用于告知对项列进行改变的原因。  //创建进度表  Scheduleschedule=newSchedule();  schedule.NamespaceName=″SampleUserCode″;  schedule.ID=″MySchedule″;  //创建作用域  Scopescope=newScope();  scope.ID=″MyScope″;  schedule.Activities.Add(scope);  //创建将发出某些内容的发送活动  Sendsend1=newSend();<!--SIPO<DPn="76">--><dpn="d76"/>  send1.ID=″send1″;  send1.Message.Name=″msg1″;  send1.Message.Type=typeof(System.String).FullName;  send1.HasTypedChannel=true;  send1.TypedChannel.Name=″port1″;  send1.TypedChannel.Type=typeof(SampleUserCode.IFoo).FullName;  send1.TypedChannel.Operation=″Foo″;  scope.Activities.Add(send1);  //创建将在进度表执行中安置延迟的延迟活动  DelayDecldelay1=newDelayDecl();  delay1.ID=″delay1″;  delay1.TimeoutProvider.Name=″delay1_TimeoutProvider″;  schedule.Activities.Add(delay1);  //创建接收活动  Receivereceive1=newReceive();  receive1.ID=″receive1″;  receive1.Message.Name=″msg2″;  receive1.Message.Type=typeof(string).FullName;  receive1.HasTypedChannel=true;  receive1.TypedChannel.Name=″port2″;  receive1.TypedChannel.Type=typeof(SampleUserCode.IFoo).FullName;  receive1.TypedChannel.Operation=″Foo″;  scope.Activities.Add(receive1);Xoml编译器Xoml编译器用于编译Xoml文件并为它产生运行时代码。由Xoml编译器给出的错误由XomlCompilerError(Xoml编译器错误)呈现。编译器还用XomlCompilerParameter(Xoml编译器参数)作为输入。编译器结果由XomlCompilerResults(Xoml编译器结果)给出。Xoml编译器反序列化xoml文件,并且随后走查活动图。它要求每个活动在一个给定的上下文中确认其自身。如果活动希望参加确认,则它从IActivityValidator(活动确认器接口)继承。如果没有由任何活动给出错误,则它要求每个活动为它自己生成代码。如果活动希望参加代码生成,则它从IActivityCodeGenerator(活动代码生成器接口)继承。XomlCompiler(Xoml编译器)类Xoml编译不同于许多其它语言编译器。Xoml编译器用xoml文件、用户代码文件作为输入,并且生成运行时过程代码。下面是涉及Xoml编译的步骤1)反序列化所有Xoml文件,并在它之外创建活动图。2)基于程序集引用,将用户代码文件和代码编译单元以参数的形式传递给编译器,创建TypeProvider(类型供应者)组件。3)走查每个单独xoml文件的活动图,并且调用它们上面的确认。4)如果没有确认错误,则在每个xoml活动图的最顶层活动上调用IActivityCodeGeenrator.GenerateCode,它将生成CodeStatementCollection(代码语句集合)。5)或者给出所生成的过程代码的CodeCompileUnit(代码编译单元),或者用传入的用户代码来编译过程代码并且使用C#和VB编译器构建程序集。下面是XomlCompiler上可用的公有方法。  publicclassXomlCompiler  {  XomlCompilerResultsCompileFromDom(XomlCompilerParametersparameters,  SchedulescheduleDecl);  XomlCompilerResultsCompileFromDomBatch(XomlCompilerParameters  parameters,Schedule[]scheduleDecls);  XomlCompilerResultsCompileFromFile(XomlCompilerParametersparameters,  stringfile);  XomlCompilerResultsCompileFromFileBatch(XomlCompilerParameters  parameters,string[]files);  XomlCompilerResultsCompileFromSource(XomlCompilerParameters  parameters,stringxomlSource);  XomlCompilerResultsCompileFromSourceBatch(XomlCompilerParameters  parameters,string[]xomlSources);<!--SIPO<DPn="78">--><dpn="d78"/>  voidGenerateSkeletonCompanionCode(Scheduleschedule,SupportedLanguages  language,System.IO.TextWriterwriter);  voidGenerateSkeletonCompanionCode(stringfile,SupportedLanguages  language,System.IO.TextWriterwriter);  }CompileFromDom(从Dom编译)方法XomlCompilerResultsCompileFromDom(XomlCompilerParametersparameters,SchedulescheduleDecl);CompileFromDom只用单个Schedule作为输入参数,并且编译它以生成过程代码。该函数方便了想要一次编译一个进度表的用户。该函数内部地调用CompileFromDomBatch(从Dom批编译)。CompileFromDomBatch方法XomlCompilerResultsCompileFromDomBatch(XomlCompilerParametersparameters,Schedule[]scheduleDecls);CompileFromDomBatch用多个Schedule作为输入参数,并且编译它们以生成过程代码。CompileFromFile(从文件编译)方法XomlCompilerResultsCompileFromFile(XomlCompilerParametersparameters,stringfile);CompileFromFile用单个xoml文件作为输入参数。第二个参数作为到xoml文件的路径对待。该函数方便了想要一次编译一个xoml文件的用户。该函数内部地调用CompileFromFileBatch(从文件批编译)。CompileFromFileBatch方法XomlCompilerResultsCompileFromFileBatch(XomlCompilerParametersparameters,string[]files);CompileFromFileBatch用多个xoml文件作为输入,并且编译它们以生成过程代码。第二个参数是到xoml文件的路径数组。该函数反序列化所有xoml文件。如果XOML文件不能被反序列化,则它将SerializationError(序列化错误)添加到编译器结果中的Errors(错误)集合。它调用CompileFromDomBatch(从Dom批编译)函数来进行编译。CompileFromSource(从源编译)方法XomlCompilerResultsCompileFromSource(XomlCompilerParametersparameters,stringxomlSource);CompileFromSource用Xoml文件的文本作为输入参数,并且编译它以生成过程代码。该函数调用CompileFromSourceBatch(从源批编译)来执行实际的编译。CompileFromSourceBatch方法XomlCompilerResultsCompileFromSourceBatch(XomlCompilerParametersparameters,string[]xomlSources);CompileFromSourceBatch用多个xoml文件源作为输入参数,并且编译它们以生成过程代码。它反序列化源以取得活动DOM。如果存在反序列化错误,则它将那些错误转换成XomlCompileError(Xoml编译错误),并且通过XomlCompilerResults(Xoml编译器结果)来报告它们。GenerateSkeletonCompanion(产生程序框架同伴)方法voidGenerateSkeletonCompanionCode(Scheduleschedule,SupportedLanguageslanguage,System.IO.TextWriterwriter);该函数用于基于在活动dom中使用的处理程序、变量,来生成程序框架用户代码分离文件。该函数走查活动图,并且生成作用域、变量和处理程序的模板代码。第二个参数告知需要用于生成代码的语言。第三个参数是文本编写器,它保存将用于写入所生成的代码的缓冲区。voidGenerateSkeletonCompanionCode(stringfile,SupportedLanguageslanguage,System.IO.TextWriterwriter);该函数用xoml文件路径作为输入参数。该函数反序列化xoml文件,并调用先前的函数。XomlCompilerParameters(Xoml编译器参数)XomlCompilerParameters具有将用户代码传入到编译器的属性。下面是XomlCompilerParameter的公用接口。publicclassXomlCompilerParametersCompilerParameters  {  boolGenerateCodeCompileUnitOnly{get;set;}  boolGenerateDebugCode{get;set;}  SupportedLanguagesLanguageToUse{get;set;}  StringCollectionLibraryPaths{get;}  IServiceProviderServiceProvider{get;set;}  IList<CodeCompileUnit>UserCodeCompileUnits{get;}  StringCollectionUserCodeFiles{get;}  }GenerateCodeCompileUnitOnly(仅生成代码编译单元)属性  boolGenerateCodeCompileUnitOnly{get;set;}该标志用于告诉编译器,用户只对生成CodeCompileUnit感兴趣,而不是可执行代码或dll。在这种情况下,编译器不调用C#或者VB编译器来生成代码。GenerateDebugCode(产生调试代码)属性boolGenerateDebugCode{get;set;}该标志用于告知是否应使用调试代码。LanguageToUse(使用的语言)属性SupportedLanguagesLanguageToUse{get;set;}至少支持两种语言VB和C#。编译器需要知道要使用的语言,因为它有许多确认是基于语言的。LibraryPaths(库路径)属性StringCollectionLibraryPaths{get;}这是目录名集合,在这些目录之下编译器将探查所引用的程序集。请注意,编译器还将一些标准库路径添加到这个集合以解析程序集引用。这种行为与C#和VB编译器相似。ServiceProvider(服务供应者)属性IServiceProviderServiceProvider{get;set;}该属性只在编译器从项目系统调用时使用。该属性的目的是要在从项目系统调用编译时达到性能。由于项目系统具有在每一项目的基础上创建的TypeProvider(类型供应者),因此编译器使用相同的TypeProvider。这在从项目系统调用时显著地提高了编译器的性能。UserCodeCompileUnits(用户代码编译单元)属性IList<CodeCompileUnit>UserCodeCompileUnits{get;}该属性用于将用户代码分离文件的代码编译单元传递给编译器。UserCodeFiles(用户代码文件)属性StringCollectionUserCodeFiles{get;}该属性用于将用户代码分离文件的文件路径传递给编译器。XomlCompilerResults(Xoml编译器结果)XomlCompilerResults具有检索所生成过程代码的CodeCompileUnit的属性。下面是XomlCompilerResults的公用接口publicclassXomlCompilerResultsCompilerResults{CodeCompileUnitCompiledUnit{get;set;}}CompiledUnit(经编译单元)属性提供对过程代码的访问。XomlCompilerError(Xoml编译器错误)XomlCompilerError具有取UserData(用户数据)属性的方法,它是Dictionary(词典)类型。该属性的目的是要插入关于错误的额外细节。例如,如果属性确认之一在一个活动上失败,将具有typeof(string)的属性名作为词典的关键字。下面是该类展示的公用接口publicclassXomlCompilerErrorCompilerError{System.Collections.IDictionaryUserData{get;}}XomlCompilerError还实现IWorkflowError(工作流错误)接口,该接口的目的是要提供错误的COM互操作性。下面是IWorkflowError接口的定义publicinterfaceIWorkflowError{StringDocument{get;}boolIsWarning{get;}StringText{get;}StringErrorNumber{get;}intLineNumber{get;}intColumnNumber{get;}}这些属性被映射到在System.CodeDom中定义的CompileError(编译错误)类的属性。确认基础结构每个活动从具有Validate(确认)方法的IActivity(活动接口)继承。Validate方法采用IServiceProvider。例如,ITypeProvider确定作为活动属性的类型名字是否可被解析成实际类型。确认方法返回IValidationError(确认错误接口)集合。下面是Validate方法的签名IValidationError[]Validate(IServiceProvidercontext);下面是IValidationError上可用的公用方法publicinterfaceIValidationError{stringErrorText{get;}IDictionaryUserData{get;}}示例确认例程下面是DelayDecl(延迟声明)活动的确认例程的例子。Delay想要确认TimeoutProvider处理程序实际上不是空,并且方法名字存在于父作用域类中。publicoverrideIValidationError[]Validate(IServiceProvidercontext){ArrayListValidationErrors=newArrayList(base.Validate(context));//确认TimeoutProvider属性ValidationErrors.AddRange(this.TimeoutProvider.Validate(context,this,″TimeoutProvider″));return(IValidationError[])ValidationErrors.ToArray(typeof(IValidationError));}以及下面是HandlerDeclaration的确认例程  publicoverrideIValidationError[]Validate(IServiceProvidercontext,IActivity  activityDecl,stringpropName)  {if(context==null)thrownewArgumentNullException(″context″);  if(activityDecl==null)thrownewArgumentNullException(″activityDecl″);  ArrayListvalidationErrors=newArrayList();  stringmessage=string.Empty;  if(this.Name==null||this.Name.Length==0)  {message=SR.GetString(SR.Error_PropertyNotSet,propName);}  else  {stringmethodName=string.Empty;  TyperesolvedType=XomlValidationHelper.ParseInputName(context,  activityDecl,this.Name,outmethodName);  if(resolvedType==null)  {message=SR.GetString(SR.Error_TypeNotResolvedInMethodName,  propName);}  else  {//取调用方法  MethodInfoinvokeMethod=this.RuntimeType.GetMethod(″Invoke″);  if(invokeMethod==null)  thrownew<!--SIPO<DPn="84">--><dpn="d84"/>  Exception(SR.GetString(SR.Error_DelegateNoInvoke,  this.RuntimeType.FullName));  //解析该方法  List<Type>paramTypes=newList<Type>();  foreach(ParameterInfoparamInfoininvokeMethod.GetParameters())  paramTypes.Add(paramInfo.ParameterType);  BindingFlagsbindingFlags=BindingFlags.Public|  BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.Static;  MethodInfomethodInfo=resolvedType.GetMethod(methodName,  bindingFlags,null,paramTypes.ToArray(),null);  if(methodInfo==null)  {if(resolvedType.GetMethod(methodName,bindingFlags)!=null)  message=SR.GetString(SR.Error_MethodSignatureM  ismatch,propName);  elsemessage=SR.GetString(SR.Error_MethodNotExists,  propName,methodName);}  elseif(!invokeMethod.ReturnType.Equals(methodInfo.ReturnType))  {message=SR.GetString(SR.Error_MethodReturnTypeMismatch,  propName,invokeMethod.ReturnType.FullName);}}}  IValidationErrorerror=null;  if(message.Length>0)  {error=newValidationError(message);  error.UserData[typeof(string)]=propName;  validationErrors.Add(error);}  return(IValidationError[])validationErrors.ToArray(typeof(IValidationError));}运行时代码生成Xoml编译器用名字空间作为进度表上的NamespaceName(名字空间名)属性,并用类名作为进度表上的ID属性,来生成Schedule类。随后它将Schedule对象序列化成xoml串,并且用其上的XomlAttribute(Xoml元属性)注释进度表类,其中第一个参数是xoml串。下面的示例代码创建ScheduleDecl(进度表声明)对象,并且创建包含用户代码的CodeCompileUnit对象。它还向Xoml编译器给予Schedule对象和UserCode。具体地说,下面的代码创建进度表。Scheduleschedule=newSchedule();  schedule.NamespaceName=″SampleUserCode″;  schedule.ID=″MySchedule″;  Scopescope=newScope();  scope.ID=″MyScope″;  schedule.Activities.Add(scope);  Sendsend1=newSend();  send1.ID=″send1″;  send1.Message.Name=″msg1″;  send1.Message.Type=typeof(System.String).FullName;  send1.HasTypedChannel=true;  send1.TypedChannel.Name=″port1″;  send1.TypedChannel.Type=typeof(SampleUserCode.IFoo).FullName;  send1.TypedChannel.Operation=″Foo″;  scope.Activities.Add(send1);  Receivereceive1=newReceive();  receive1.ID=″receive1″;  receive1.Message.Name=″msg2″;  receive1.Message.Type=typeof(string).FullName;  receive1.HasTypedChannel=true;  receive1.TypedChannel.Name=″port2″;  receive1.TypedChannel.Type=typeof(SampleUserCode.IFoo).FullName;  receive1.TypedChannel.Operation=″Foo″;  scope.Activities.Add(receive1);  DelayDec1delay1=newDelayDecl();  delay1.ID=″delay1″;  delay1.TimeoutProvider.Name=″delay1_TimeoutProvider″;<!--SIPO<DPn="86">--><dpn="d86"/>  schedule.Activities.Add(delay1);下面的代码创建代码编译单元、添加名字空间、添加MySchedule(我的进度表)类并且添加延迟方法。  CodeCompileUnitccu=newCodeCompileUnit();  CodeNamespacesampleUserCode=newCodeNamespace(″SampleUserCode″);  ccu.Namespaces.Add(sampleUserCode);  /*  publicpartialclassMyScheduleSchedule  {  publicMySchedule()  {  }  }  */  CodeTypeDeclarationmySchedule=newCodeTypeDeclaration(″MySchedule″);  mySchedule.BaseTypes.Add(new  CodeTypeReference(″System.Workflow.Runtime.Schedule″));  mySchedule.IsClass=true;  mySchedule.PartialType=PartialType.Partial;  mySchedule.TypeAttributes=TypeAttributes.Public;  sampleUserCode.Types.Add(mySchedule);  /*  publicSystem.DateTimedelay1_TimeoutProvider()  {  returnnewSystem.DateTime();  }  */  CodeMemberMethoddelayMethod=newCodeMemberMethod();  delayMethod.Name=″delay1_TimeoutProvider″;<!--SIPO<DPn="87">--><dpn="d87"/>  delayMethod.Attributes=(MemberAttributes.Public|MemberAttributes.Final);  delayMethod.ReturnType.BaseType=typeof(System.DateTime).FullName;  delayMethod.Statements.Add(newCodeMethodReturnStatement(new  CodeSnippetExpression(″newSystem.DateTime();″)));  mySchedule.Members.Add(delayMethod);下面所示的代码编写MyScope(我的作用域)类并且添加一个字段。  /*  publicpartialclassMyScopeScope  {  }  */  CodeTypeDeclarationmyScope=newCodeTypeDeclaration(″MyScope″);  myScope.BaseTypes.Add(new  CodeTypeReference(″System.Workflow.Runtime.Scope″));  myScope.IsClass=true;  myScope.PartialType=PartialType.Partial;  myScope.TypeAttributes=TypeAttributes.Public;  sampleUserCode.Types.Add(myScope);  /*  publicSystem.Workflow.Runtime.OEMessage<System.String>msg1;  public  System.Workflow.Runtime.OEOutboundChannel<SampleUserCode.IFoo>  port1;  publicSystem.Workflow.Runtime.OEMessage<System.String>msg2;  publicSystem.Workflow.Runtime.OEInboundChannel<IFoo>port2;  */  CodeMemberFieldmsg1=new  CodeMemberField(″System.Workflow.Runtime.OEMessage<System.String>″,  ″msg1″);<!--SIPO<DPn="88">--><dpn="d88"/>  msg1.Attributes=MemberAttributes.Public;  myScope.Members.Add(msg1);  CodeMemberFieldport1=new  CodeMemberField(″System.Workflow.Runtime.OEOutboundChannel<SampleU  serCode.IFoo>″,″port1″);  portl.Attributes=MemberAttributes.Public;  myScope.Members.Add(port1);  CodeMemberFieldmsg2=new  CodeMemberField(″System.Workflow.Runtime.OEMessage<System.String>″,  ″msg2″);  msg2.Attributes=MemberAttributes.Public;  myScope.Members.Add(msg2);  CodeMemberFieldport2=new  CodeMemberField(″System.Workflow.Runtime.OEInboundChannel<SampleUse  rCode.IFoo>″,″port2″);  port2.Attributes=MemberAttributes.Public;  myScope.Members.Add(port2);下面的代码生成最终的C#代码。具体地说,代码结合来自用户代码的CCU和XOMLOM的CCU来生成程序集。XomlCompilercompiler=newXomlCompiler();XomlCompilerParametersparameters=newXomlCompilerParameters();parameters.ReferencedAssemblies.Add(typeof(SampleUserCode.IFoo).Assembly.Location);parameters.UserCodeCompileUnits.Add(ccu);parameters.OutputAssembly=@″c\CreateAssemblyWithUserCodeInCodeDOM.dll″;XomlCompilerResultsresults=compiler.CompileFromDom(parameters,schedule);错误导航基础结构当Xoml编译器被调用时,如果存在任何错误,则它返回IWorkflowError(工作流错误接口)对象的集合。对于每个IWorkflowError对象,创建一个任务项。下面是将错误导航到设计器上所涉及的步骤,当用户双击任务项时1)每个任务项与一个IWorkflowError对象相关联。2)在双击第一个时,它通过调用IWorkflowError.Document属性来取得文件名。3)它要求设计器打开文件并且取得与其相关联的DocView(文档视图)对象。4)它查找DocView(文档视图)上的IWorkflowErrorNavigator(工作流错误导航接口)接口。5)它调用IWorkflowErrorNavigator.Navigate()方法,并且传递IWorkflowError作为第一个参数。6)IWorkflowErrorNavigator接口在文档视图对象上实现。在Navigate(导航)方法的实现中,编辑器试图查找IWorkflowError中UserData属性中的“typeof(IActivity)”对象,如果找到,则它取得活动的作用域合格的名字,并且搜索设计器具有相同名字的活动。如果找到一个活动,则聚焦于它。在它查找UserData属性中的‘typeof(string)’关键字之后,如果找到,则假定应它是需要聚焦的属性名,因此它通过传递属性名作为第一个变元来调用IExtUIService.NaviagteToProperty()方法。下面是IWorkflowErrorNavigator的定义。internalinterfaceIWorkflowErrorNavigator{voidNavigateToError([MarshalAs(UnmanagedType.IUnknown)]objectobj);}工作流编译器可执行代码(即WFC.EXE)Wfc.exe是一个产品二进制码,它是XomlCompiler的命令行版本。该可执行码对命令行变元进行语法分析,并且填充XomlCompilerParameters结构。下面是可传递给XomlCompiler的选项的定义。  wfc.exe<schedule>.xoml/targetcodebeside[/language...]  wfc.exe<schedule>.xoml/targetxomlclass[/language...]  wfc.exe<schedule>.xoml/targetassembly[<codebeside>.cs][/language...]<!--SIPO<DPn="90">--><dpn="d90"/>  [/out...][/reference...][/library...][/debug...]  -输出文件-  /out<file>输出文件名  /targetassembly构建工作流程序集(默认)。  /targetxomlclass生成部分类定义。  /targetcodebeside生成程序框架分离代码。   -输入文件-  <xomlfilelist>Xoml源文件名。  <vb/csfilelist>代码分离文件名。  /reference<filelist>引用来自指定程序集文件的元数据。  简短形式是′/r′。  /library<pathlist>目录集,在其中查找这些引用。  简短形式是′/lib′。  -代码生成-  /debug[yes|no]发出完全调试信息。默认是′yes′。   简短形式是′/d′.  /skipvalidation[+|-]跳过工作流确认。  /emitruntimecode[+|-]发出工作流的运行时代码。  -语言-  /language[cs|vb]用于所生成的类的语言。  默认为′CS′(C#)。简短形式是′/l′。  /rootnamespace<string>指定所有类型声明的根名字空间。  仅对于′VB′(VisualBasic)语言有效。  -杂项-  /help显示用法消息。简短形式是′/?′。  /nologo禁止编译器的版权消息。简短形式是′/n′。类型系统类型系统是设计器中独立的组件。CodeCompileUnit和程序集可压入类型系统中。它从程序集引用中加载System.Type对象,并且将它们压入类型树。而且对于CodeCompileUnit中每个CodeTypeDeclaration(代码类型声明)对象,它创建从System.Type继承的DesignTimeType(设计时类型),并将它们压入类型树。这样,来自类型系统的类型由公共的抽象类System.Type来展示。像许多其它类型系统一样,它在加载类型到系统中时创建树结构,这使类型解析非常快。类型系统在类型树上提供用户接口以解析类型,而且,它激发事件来通知关于类型树中的改变。下面是类型系统中的主要组件1.TypeProvider(类型供应者)它具有添加/移除程序集引用并将CodeCompileUnit(代码编译单元)添加到类型系统的公用方法。而且,它实现了向用户展示类型树的接口。a.TreeNode(树节点)树节点是类型树中的一般节点。它保存与它相关联的所有类型定义。2.CodeDOMLoader(代码DOM加载器)CodeDOMLoader从CodeCompileUnit加载所有类型,并且将它们压入类型树。在处置CodeDOM(代码DOM)加载器时,它移除它添加到类型树的所有类型。3.AssemblyLoader(程序集加载器)程序集加载器从程序集加载所有类型,并且将所有类型压入类型树。在处置它时,将从类型树移除所有类型。4.DesignTimeType(设计时类型)该类从System.Type继承。它用CodeTypeDeclaration代码DOM构造作为它的构造函数变元,并且实现System.Type类的所有属性和方法。而且下面的类用于从CodeTypeDeclaration转换成System.Type。a.DesignTimeMethodInfo(设计时方法信息)该类用于基于CodeMemberMethod(代码成员方法)实现MethodInfo(方法信息)的所有成员。i.DesignTimeParamterInfo(设计时参数信息)该类从ParameterInfo(参数信息)继承,并且提供基于CodeParameterDeclarationExpression代码DOM构造的实现。b.DesignTimeEventInfo(设计时事件信息)该类用于基于CodeMemberEvent(代码成员事件)实现EventInfo(事件信息)的成员。c.DesignTimeFieldInfo(设计时字段信息)该类从FieldInfo(字段信息)继承,并且提供基于CodeMemberField(代码成员字段)的所有方法。d.DesignTimePropertyInfo(设计时属性信息)该类从PropertyInfo(属性信息)继承,并且提供基于CodeMemberProperty代码dom构造的所有方法和属性的实现。e.DesignTimeConstructorInfo(设计时构造函数信息)该类从ConstructorInfo(构造函数信息)继承,并且提供基于CodeMemberMethod的所有方法和属性的实现。f.AttributeInfo(元属性信息)AttributeInfo类用于保存关于类型上的元属性的信息。类型供应者组件类型供应者是类型系统中的顶层组件。可创建类型供应者的实例。类型供应者保持类型树的根节点。在向类型供应者添加程序集引用和代码编译单元时,它从它们加载所有类型,并且将它们加载到类型树。这里例如如果有来自一个程序集的下列类型Art.Bar.ZooArt.Peter.BazSystem.String则相应的树结构看上去如下Art--Bar--Zoo--Peter--BazSystem--String每个节点保持它所指向的类型定义列表。例如,在上面的情况下,String节点将包含System.String类型。类型定义列表在每个节点上保持。在类型系统可以有重复的类型。下面是类型供应者的公用方法。AddAssemblyReference(添加程序集引用)方法publicvoidAddAssemblyReference(stringpath)该方法用于将程序集引用添加到类型系统。来自该程序集的所有类型将被加载到类型系统。RemoveAssemblyReference(移除程序集引用)方法publicvoidRemoveAssemblyReference(stringpath)该方法用于从类型系统中移除程序集引用。从该程序集加载到类型树的所有类型将被移除。AddCodeCompileUnit(添加代码编译单元)方法publicvoidAddCodeCompileUnit(CodeCompileUnitcodeCompileUnit)该方法用于将CodeCompileUnits加载到类型系统。这将经历代码编译单元中的所有CodeTypeDeclarations,并且将为它们的每一个创建从System.Type继承的合适的DesigntimeType。并且DesignTimeType(设计时类型)将被加载到类型系统。RemoveCodeCompileUnit(移除代码编译单元)方法publicvoidRemoveCodeCompileUnit(CodeCompileUnitcodeCompileUnit)该方法用于从类型系统卸载CodeCompileUnit。所有从CodeCompileUnit加载的类型将被移除。RefreshCodeCompileUnit(刷新代码编译单元)方法publicvoidRefreshCodeCompileUnit(CodeCompileUnitcodeCompileUnit,CodeCompileUnitRefreshHandlerrefresher)该方法用于刷新类型系统中的代码编译单元。它与从类型系统移除编译单元一样,并且随后将它添加回类型系统。ITypeProvider(类型供应者接口)接口该服务用于访问和解析主存环境的类型系统中的类型。这是由TypeProvider组件展示的接口。ITypeProvider是由TypeProvider向用户展示的接口。它用于解析类型系统中的类型。下面是该接口的定义  publicinterfaceITypeProvider<!--SIPO<DPn="94">--><dpn="d94"/>  {  TypeGetType(stringname);  TypeGetType(stringname,boolthrowOnError);  Type[]GetTypes();  StringCollectionTypeLoadErrors  {  get;  }  eventEventHandlerTypesChanged;  eventEventHandlerTypeLoadErrorsChanged;  }下面是涉及在设计器中主存TypeProvider的组件描述TypeProviderHost(类型供应者宿主)组件TypeProviderHost(类型供应者宿主)是用于在每一对象的基础上维护类型系统的主要组件。TypeProviderHost保存项目系统指针和对应的TypeProvider。它通过对所有用户代码文件进行语法分析将一个CodeCompileUnit压入类型系统。它还兼通可修改包含在类型系统中的类型的所有项目系统事件。下面是由TypeProviderHost完成的体系结构工作1.分析用户代码文件并且创建CodeCompileUnit。(FileCodeModel(文件代码模型)到CodeDOM)2.监听项目系统中的事件,并且对TypeProvider作出适当调用以刷新类型这里是它监听的事件列表和它所作的对应的TypeProvider调用以通知改变。ILangFileEvents(语言文件事件接口)跟踪这些事件以发现项目中的文件添加、移除、移动、构建动作改变等等。当这些事件的任一个发生时,类型供应者刷新CodeCompileUnit。_dispCodeModelEvents(显示代码事件)每当新的CodeElement(代码元素)被添加到用户代码文件时,这些事件由VisualBasic的文件代码模型激发。这些事件只对visualbasic项目系统有意义,在C#项目系统中不激发相似的事件。_dispReferencesEvents(显示引用事件)这些事件在从项目添加或者移除程序集引用时激发。在得到添加程序集引用事件时,程序集被添加到对应的TypeProvider。在得到移除程序集引用事件时,从类型系统移除程序集引用。_dispBuildEvents(显示构建事件)跟踪构建事件以发现项目一项目引用情况。在这类情况下,当构建一个引用的项目时,从类型系统中移除旧的程序集,并且将新的程序集刷新到TypeProvider中以从它加载新类型。_IVsRunningDocTableEvents(IV正在运行文档表事件)为多个目的跟踪正在运行文档表事件。例如,当在编辑器中改变文档,关闭但没有保存它,则类型系统还原到未保存状态,因为类型系统没有用文件中的改变来更新。当在编辑器中打开一个文档用于编辑时,本发明监听IVsTextStreamEvents(IV文本流事件)以获得这些事件并且刷新代码编译单元。_IVsTextStreamEvents(IV文本流事件)这些事件用于监听由用户完成的文件编辑。ITypeProviderCreator(类型供应者创建者接口)服务ITypeProviderCreator(类型供应者创建者接口)服务是在设计器包级上展示的。使用该服务可获得项目的TypeProvider。下面是ITypeProviderCreator的接口定义publicinterfaceITypeProviderCreator{ITypeProviderGetTypeProvider(objectobj);}该服务由配合设计器包实现。该服务的实现监听IVsSolution(IV解决方案)事件,并且为解决方案中的每个项目维护一个类型供应者宿主。该服务还在第一次需要它时为项目创建TypeProviderHost(类型供应者宿主)。使用该服务,开发者获得任何项目的类型系统。而且在解决方案关闭时,该服务摧毁系统中所有TypeProviderHost。在关闭项目时,该服务从系统中移除所有对应的TypeProviderHost。配合引擎工具箱页面缓冲由二进制文件中的程序集分类的工具箱条目。当被激活时,这些条目被加载到页面中。复选工具箱中的项以指示它们是否由工具箱显示。用户可通过选择浏览按钮从不同的程序集添加新工具箱项。浏览按钮带出文件选择对话框,其中用户选择一个可从其中加载附加的工具箱项的程序集。工具箱页面在单独的应用程序域中加载用户选择的程序集,并且通过调用ToolboxService.GetToolBoxItems从它获得所有工具箱项。随后跨域对这些项编组,并且将它们加载到工具箱页面中。这么做使得用户程序集不被加载到主要域并被锁定。用户随后可复选和不复选需要在工具箱中显示的工具箱项。当对话框关闭时,工具箱页面使用ToolboxService.AddToolBoxItems和ToolboxService.RemoveToolBoxItems基于其复选状态从工具箱添加和移除项。工具箱页面还序列化二进制文件中被更新的工具箱条目,因此在下次显示工具箱页面时加载它们。GetType(取类型)方法TypeGetType(stringname);该方法用于解析类型树中的类型。用户以“A.B.C”的形式传入一个串,其中A.B是名字空间,而C是该名字空间中的类型名字。该方法可返回“空”,它表示具有以下名字的类型不能被解析。GetType(取类型)重载方法TypeGetType(stringname,boolthrowOnError);该方法与上面的方法相同,唯一的不同是它在找不到类型时抛出异常。GetTypes(取类型)方法Type[]GetTypes();该方法用于检索类型系统中存在的所有类型。TypeLoadErrors(类型加载错误)属性StringCollectionTypeLoadErrors{get;}在将类型加载到类型供应者上时,它可能陷入某些问题,例如,它不能解析程序集引用。在那些情况下,TypeLoadErrors属性返回所有类型加载错误。TypesChanged(类型被改变)事件eventEventHandlerTypesChanged;每当新程序集引用或者代码编译单元被添加到类型系统时,该事件将被激发给用户,告知类型系统中的类型被改变。这是一个一般事件,这意味着它不提供关于添加或者移除哪些类型的任何具体信息。延迟加载基础结构类型系统具有延迟加载能力。添加到TypeProvider的程序集引用和CodeCompileUnits在需要从类型树解析类型之前不被加载。因此,AddAssemblyReference(添加程序集引用)和AddCompileUnit(添加编译单元)中的代码高速缓存程序集路径和CodeCompileUnit,并且激发TypesChanged事件。没有一个类型被加载,直到并且除非需要它们。该技术改进类型系统的性能。由于这个原因,在类型加载失败时不抛出异常。相反,激发TypeLoadErrors。下面的代码片断说明如何创建TypeProvider(类型供应者)组件  //创建代码编译单元  CodeCompileUnitccu=newCodeCompileUnit();  //添加名字空间  CodeNamespacesampleUserCode=newCodeNamespace(″SampleUserCode″);  ccu.Namespaces.Add(sampleUserCode);  CodeTypeDeclarationmySchedule=newCodeTypeDeclaration(″MySchedule″);  mySchedule.BaseTypes.Add(new  CodeTypeReference(″System.Workflow.Runtime.Schedule″));  mySchedule.IsClass=true;  mySchedule.PartialType=PartialType.Partial;  mySchedule.TypeAttributes=TypeAttributes.Public;  sampleUserCode.Types.Add(mySchedule);  //创建类型供应者  TypeProvidertypeProvider=newTypeProvider(null);  typeProvider.AddAssemblyReference(Assembly.GetExecutingAssembly().Locati  on)  typeProvider.AddCodeCompileUnit(ccu);XomlSerializer(Xoml序列化器)类与活动相关联的序列化器组件从XomlSerializer继承。XomlSerializer还是活动的默认序列化器组件。它在活动属性上反射并且序列化它们。对于合成活动,默认的序列化器组件是CompositeXomlSerializer(合成Xoml序列化器),它除了基本Xoml序列化之外,还序列化子活动。该类中的函数可被进一步分类成用于序列化和反序列化xoml文件的公用函数、用于控制对象的序列化的函数、以及用于控制对象的反序列化的函数。序列化/反序列化XOML文件的公用函数publicobjectDeserialize(XmlTextReaderreader)给定一个XmlTextReader(Xml文本阅读器)对象,该方法反序列化它并且返回一个对象。XmlTextReader指向xml元素。这是反序列化xoml文件的公用方法。publicobjectDeserialize(IDesignerSerializationManagersm,XmlTextReaderreader)给定TextReader(文本阅读器)和IDesignerSerializationManager(设计器序列化管理器接口),该方法反序列化活动。IDesignerSerializationManager对象可用于提供对象的自定义反序列化器,并且还解析类型。publicvoidSerialize(objectobj,XmlTextWriterwriter)该方法将第一个参数中指定的对象序列化成XmlTextWriter(Xml文本编写器)对象。publicvoidSerialize(IDesignerSerializationManagersm,objectobj,XmlTextWriterwr);该方法将对象序列化到XmlTextWriter对象。它采用可用于解析类型等的附加设计器序列化管理器对象。反序列化对象protectedobjectDeserializeObject(IXomlSerializationManagersm,XmlTextReaderrd);该方法反序列化元素并且创建对象。它使用xmlns到CLR名字空间和程序集的映射来解析对象的类型,并且随后给予与该类型相关联的序列化器组件创建该类型的实例的机会。XomlSerializer的CreateInstance(创建实例)方法用于创建对象的实例,它可在导出类中被覆盖。XmlTextReader必须指向一个元素节点,否则该方法抛出异常。该方法在创建对象的实例之后调用DeserializeContents(反序列化内容)。protectedvoidDeserializeContents(IXomlSerializationManagersm,objectobj,XmlTextReaderrd);该方法用于反序列化对象的属性和子对象。它用对象和XmlTextReader作为参数。XmlTextReader指向XmlElement(Xml元素)节点。它经历元素的所有元属性并且调用序列化器上的DeserializeSimpleProperty()(反序列化简单属性)。DeserializeSimpleProperty可被覆盖以进行属性的自定义反序列化。之后,它经历元素的所有子元素,并且将它们或者识别为子对象或者识别为属性。在将一个子元素识别为属性时,它调用序列化器上的DeserializeCompoundProperty()(反序列化复合属性),否则它调用DeserializeObject()(反序列化对象)来反序列化子元素,并且添加所返回的对象作为主对象的子对象。为添加所返回的对象作为子对象,它调用序列化器上的AddChild()(添加子对象)方法,它可被覆盖以实现不同的父-子关系。protectedvirtualvoidDeserializeSimpleProperty(IXomlSerializationManagersm,objectobj,XmlTextReaderrd);该方法由DeserializeContents()调用以反序列化简单属性。简单属性为其一部分的对象和XmlTextReader作为参数传递。XmlTextReader指向一个元属性。元属性名作为属性的名字来对待。protectedvirtualvoidDeserializeCompoundProperty(IXomlSerializationManagersm,objectobj,PropertyDescriptorpd,XmlTextReaderrd);该方法由DeserializeContents()调用以反序列化复合属性。传递给它的是对象、属性描述符和XmlTextReader。XmlTextReader指向XmlElement。属性可以是只读的或者非只读的。如果属性是只读的,则调用属性上的取值方法,它将给出对象,现在调用该对象上DeserializeContens以反序列化对象的内容。如果属性是读写的,则它可有且只有一个子元素。反序列化第一个子元素并且在属性上设置所返回的对象。序列化对象protectedvoidSerializeObject(IXomlSerializationManagers,objecto,XmlTextWriterwr);该方法被调用以序列化对象。传递给它的是需要被序列化的对象和必须在其上编写序列化内容的XmlTextWriter。该方法为对象构造XmlQualifiedName(Xml合格名字),它实际上是对象类型的xml名字空间和类名。Xml名字空间使用对象类型的程序集和名字空间信息来构造。它用该合格名字来编写xml元素的开始,并且随后调用SerializeContents()(序列化内容)来进一步序列化化对象的属性和子对象。并且它调用EndElement(结束元素)来关闭该元素。protectedvoidSerializeContents(IXomlSerializationManagers,objecto,XmlTextWriterw);该方法被调用以序列化对象的所有属性和子对象。传递给该方法的是对象和指向Xml元素的XmlTextWriter。它查找对象的序列化器组件并且调用其上的GetProperties()(取属性)来取对象的属性。它查找属性上的DesignerSerializationVisibility(设计器序列化可见性)元属性,如果Visibility(可见性)被设置为Visible(可见),则将属性作为简单属性对待,并且调用SerializeSimpleProperty(序列化简单属性),如果Visibility设置为Content(内容),则将属性作为复合属性对待。并且调用SerializeCompoundProperty()(序列化复合属性),否则如果可见性设置为Hidden(隐藏),则忽略该属性。它还检查属性的DefaultValue(默认值)元属性,如果属性的DefaultValue是相同的属性值,则跳过该属性。它调用对象的序列化器组件上的GetChildren()(取子对象)以取得所有子对象。它随后使用SerializeObject()来序列化子对象。protectedvirtualvoidSerializeSimpleProperty(IXomlSerializationManagersm,objectobj,PropertyDescriptorpd,stringparentPropName,XmlTextWriterwr);传递给该方法的是需要被串行化的对象、属性的PropertyDescriptor(属性描述符)和XmltextWriter对象。该函数在XmlTextWrite上通过使用属性名字作为元属性名字,并使用属性值作为元属性值,来编写xml元属性。protectedvirtualvoidSerializeCompoundProperty(IXomlSerializationManagersm,objectobj,PropertyDescriptorpd,XmlTextWriterwr);该方法用于序列化对象的混合属性。传递给它的是对象、属性描述符和XmlTextWriter对象。如果属性是只读的,则创建元素并且调用由属性的取值器方法调用返回的对象上的SerializeContents(),否则它编写其名字是属性的名字的起始元素,并且调用由属性的取值器方法返回的对象上的SerializeObject()。助手函数protectedvirtualIListGetChildren(objectobj);该方法用于取对象的子对象。通常对象使用不同的机制来描述父子关系。例如,ICompositeActivity使用Activities(活动)属性在编程上表示子对象。不同的序列化器可覆盖该属性,并且返回子对象的列表。默认地这返回<null>值。protectedvirtualPropertyDescriptorCollectionGetProperties(objectobj);该方法用于取对象的属性。默认地,该方法返回Browsable(可浏览)元属性设置为真且DesignerSerializationVisibility元属性没有被设置为Hidden的属性。对象序列化器组件可覆盖它,并且控制所返回的属性集合。protectedvirtualvoidAddChild(objectobj,objectchildObj);该方法用于添加父对象的子对象。它所做的与GetChildren()相反。序列化器组件可控制AddChild()实现的行为。protectedvirtualobjectCreateInstance(Typetype,XmlTextReaderrd);该方法用于创建类型的实例。默认地,它调用Activator.CreateInstance()来创建对象。但导出类可使用不同的技术用于它们的组件类型的CreateInstance(),并且它们可通过使用XmlTextReader对象来向构造函数传递某些参数。CompositeXomlSerializer(合成Xoml序列化器)类合成Xoml序列化器用于序列化合成活动。它具有来自基类的两个被覆盖的方法,用于反序列化和序列化子活动。  publicclassCompositeActivityXomlSerializerXomlSerializer  {  protectedoverrideIListGetChildren(objectobj)  {  ...变元检查  ICompositeActivitycompositeActivity=objasICompositeActivity;  return(IList)compositeActivity.Activities;  }  protectedoverridevoidAddChild(objectobj,objectchildObj)  {  ...argumentchecks  ICompositeActivitycompositeActivity=objasICompositeActivity;  IActivityactivity=childObjasIActivity;<!--SIPO<DPn="102">--><dpn="d102"/>  compositeActivity.Activities.Add(activity);  }  }IXomlSerializationManager(Xoml序列化管理器接口)接口IXomlSerializationManager从IDesignerSerializationManager类继承。在给定xml合格名字的情况下,提供附加的功能以给出活动类型,反之亦然。下面是IXomlSerializationManager的接口定义publicinterfaceIXomlSerializationManagerIDesignerSerializationManager{XmlQualifiedNameGetXmlQualifiedName(Typetype);TypeGetType(XmlQualifiedNamexmlQualifiedName);}序列化错误Xoml序列化器使用IDesignerSerializationManager.ReportError()方法添加所有反序列化错误。只要反序列化遇到错误,它只需添加错误对象,但它不停止反序列化过程,直到和除非xml格式是非法的。XomlSerializer使用XomlSerializerException(Xoml序列化器异常)类来报告反序列化错误。  publicclassXomlSerializationExceptionException  {  privateintlineNumber=-1;  privateintcolumnNumber=-1;  publicXomlSerializationException(stringmessage,intline,intcolumn)  base(message)  {  ..  }  publicXomlSerializationException(stringmessage,Exception  innerException,int  line,intcolumn)<!--SIPO<DPn="103">--><dpn="d103"/>  {  ..  }  publicXomlSerializationException(stringmessage)  {  }  publicintLineNumber{get;}  publicintLinePosition{get;}  }工作流组件模型还提供向web服务描述语言(WSDL)格式提供进度表的序列化。配合引擎设计器体系结构配合引擎设计器使用System.ComponentModel和System.ComponentModel.Design名字空间中定义的类。由配合引擎设计器使用的框架基础结构类是DesignSurface(设计表面)、DesignSurfaceManager(设计表面管理器)和DesignerLoader(设计加载器)。所有这些类都是System.ComponentModel.Design名字空间的一部分。下面的表简要地描述了该名字空间的描述和用途。表B2.System.Workflow.ComponentModel.Design.DesignSurface和DesignSurfaceManagerDesignSurface代表设计器,并且包括一组设计器需要的默认服务。DesignSurfaceManager本质上提供设计器的集合,以及那些设计器可用于通信目的的某些应用程序级服务。DesignSurface使用IServiceProvider接口展示多个服务。所展示的主要服务是IDesignerHost(设计器宿主接口)。IDesignerHost保存添加到它的组件集合,并且基于在组件上声明的DesignerAttribute(设计器元属性),为添加到它的所有组件创建设计器。添加到设计器宿主的每个组件必须从IComponent(组件接口)继承。而且被添加的第一个组件被称为根组件。根组件的设计器必须实现被称为IRootDesigner(根设计器接口)的接口。该接口具有被称为GetView()(取视图)的方法,它返回根组件的‘Control(控件)’对象。设计表面返回由根组件的GetView()在其视图属性实现中返回的Control。配合引擎设计器使用Schedule作为根组件,并且用ServiceRootDesigner(服务根设计器)作为它的根设计器。ServiceRootDesigner上的GetView()方法返回‘WorkflowView(工作流视图)’控件,它可直接主宿在主宿环境中,例如,当配合引擎设计器主宿在设计器中时,WorkflowView控件将主宿在IVsWindowPane(IV窗口窗格)的主要窗口中。DesignerLoader(设计器加载器)DesignerLoader是一个抽象类,它负责对象图的反序列化和序列化。创建设计器加载器,并且提交包含设计器的序列化状态的数据的文件或二进制块(blob)。数据与加载器之间的关系对于加载器的实现是私有的。要求设计器加载器开始加载过程。传递给它的是一个接口指针,称为IDesignerLoaderHost(设计器加载器宿主接口),它提供对知道如何创建设计器的DesignSurface的访问。IDesignerLoaderHost还提供某些共同的实用程序函数。设计器加载器解释其序列化数据袋。它创建组件的实例、将它们添加到容器、并且设置它们之上的属性。配合引擎设计器具有ServiceDesignerLoader(服务设计器加载器)作为其DesignerLoader类的实现。从Xoml文件到工作流视图的历程下面是解释如何将所有这些基础结构部件挂钩在一起以反序列化Xoml并且在窗口表单控件中显示它的伪代码。DesignSurfacesurface=newDesignSurface();ServiceDesignerLoaderloader=newServiceDesignerLoader(surface);loader.FilePath=“c\\foo.xoml”;surface.BeginLoad(loader);Controlcontrol=surface.View;以上代码首先创建一个DesignSurface。随后它创建DesignerLoader并且将表面对象传递到其构造函数中。随后它设置加载器上的FilePath(文件路径)属性。现在它要求表面使用指定的加载器开始加载。DesignSurface进而调用DesignerLoader.BeginLoad()来加载xoml文件。这使活动被添加到DesignSurface,后者进而为这些活动创建设计器并且高速缓存这些活动及其设计器。所添加的第一个组件是Schedule,它称为根组件,并且它具有相关联的ServiceRootDesigner,作为使用DesignerAttribute的设计器。IComponent和IComponent.Site添加到DesignSurface的所有组件实现IComponent。DesignSurface创建一个Site(站点)对象,并且将它设置在IComponent.Site属性上。当一个组件确定了站点时,它被称为由一个特定的容器所“拥有”。容器可通过组件的站点为组件提供服务,并且容器本身甚至可将服务请求委托给父服务供应者。IDesigner(设计器接口)和IActivityDesigner(活动设计器接口)添加到设计表面的组件具有与它们相关联的设计表面,它们实现IDesigner接口。IDesigner接口是基本的,并且所提供的功能对于所有组件是共同的。为在配合引擎DesignSurface中主宿设计器,它必须实现IActivityDesigner,它是一个被定义成完成大部分UI相关工作的接口。例如,拖/放、鼠标、键盘、布局、呈现等等。设计器通过类型DesignerAttribute的类级元属性与组件相关联。设计器由IContainer(容器接口)接口的特殊实现创建。当组件被添加到该容器时,容器将对组件的元数据搜索设计器元属性。如果存在,则设计器将被创建和初始化。设计时服务要求每个设计器用与之相关联的IComponent来初始化。IComponent.Site使设计者能够通过外部世界通信。当一个组件被添加到IDesignerHost时,设计器宿主为该组件创建一个站点,并且将它设置在IComponent.Site属性上。站点从允许设计者访问外部世界服务的IServicePovider继承。由DesignSurface(设计表面)提供的服务这些是由DesignSurface提供的标准服务。表B3.由设计器提供的服务由寄宿环境提供的服务表B4.由寄宿环境提供的服务工作流视图工作流视图是设计表面,它呈现以XOML描述的过程的可视表示。工作流视图提供活动设计器用于呈现和响应于各种窗口生成的事件所需要的丰富的UI功能集。除此之外,工作流视图提供共同的函数集,它们可由所有设计器用于执行某些活动。publicclassWorkflowViewUserControl,IDesignerService,IDesignerView,IServiceProviderSystem.ObjectSystem.MarshalByRefObjectSystem.ComponentModel.ComponentSystem.Windows.Forms.ControlSystem.Windows.Forms.ScrollableControlSystem.Windows.Forms.ContainerControlSystem.Windows.Forms.UserControl[VisualBasic]System.OrchestrationEngine.ComponentModel.Design.WorkflowViewUserControl(用户控件)用户控件使工作流视图能够重新主宿到第三方应用程序中以呈现工作流。IDesignerService(设计器服务接口)设计器服务使工作流视图能够展示使活动设计器和其它宿主能够与其交互以利用各种用户界面特征的功能。IDesignerView(设计器视图接口)设计器视图接口使工作流视图容器能够与工作流交互。使用该服务,外部容器可将其活动状态传送到工作流视图,后者响应于这些消息更新其UI状态并且可进行初始化。IServiceProvider(服务供应者接口)工作流视图用作活动设计器的服务供应者;使用工作流视图,活动设计器可获得对服务容器中提供的其它服务的访问。工作流视图是呈现以XOML描述的过程流的可视表示的设计表面。工作流视图提供活动设计器用于呈现和响应于各种窗口生成的事件所需要的丰富的UI功能集。除此之外,工作流视图提供可由所有设计器用于执行某些活动的共同的功能集。权利要求1.一种用于创作工作流的计算机化的系统,所述工作流对商业过程建模,所述计算机化的系统包括标识与工作流相关联的多个活动的包;用于选择所述多个活动的一个或多个并使它们相互关联的接口;以及用于序列化所述标识的活动以创建所述工作流的持久表示的序列化器。2.如权利要求1所述的计算机化的系统,其特征在于,还包括用于创作所述工作流的设计应用程序编程接口,其中,所述多个活动的每一个具有与其相关联的组件模型,所述组件模型指定与其相关联的活动的属性;以及用于编译通过所述设计应用程序编程接口创作的工作流的编译应用程序编程接口。3.如权利要求1-2所述的计算机化的系统,其特征在于所指定的属性包括下列的一个或多个设计时行为、编译时行为、以及运行时间行为;以及所述多个活动包括用户定义的活动,所述用户定义的活动具有一个或多个属性,并且所述系统还包括用于验证与每个所述属性相关联的格式的语义检查器。4.如权利要求1-3所述的计算机化的系统,其特征在于,所述接口接收实现与所选择的活动相关联的商业逻辑的软件代码,所述系统还包括用于将所序列化的工作流表示和所述软件代码编译成所述工作流的可执行表示的编译器,并且所述系统还包括用于执行由所述编译器创建的所述工作流的可执行表示的运行时引擎。5.如权利要求1-4所述的计算机化的系统,其特征在于,所述设计应用程序编程接口包括用于创作所述工作流的装置,以及用于选择所述活动的一个或多个以创建所述工作流的装置,并且其中,所述编译应用程序编程接口包括下列的一个或多个用于定制所述工作流的可视外观的装置;用于编译通过所述设计应用程序编程接口创作的工作流的装置;用于确认所述工作流的装置;以及用于序列化所述工作流的装置。6.如权利要求1-5所述的计算机化的系统,其特征在于,还包括用于将类型与所述工作流中的多个活动的每一个相关联的类型供应者应用程序编程接口,并且其中,所述类型供应者应用程序编程接口包括用于将所述类型与所述工作流中的多个活动的每一个相关联的装置。7.如权利要求1-6所述的计算机化的系统,其特征在于,还包括表示与所述工作流中的每个活动相关联的组件模型的数据结构,所述数据结构包括图象字段,存储可视地表示所述活动的数据;一个或多个创作时字段,存储定义与所述活动相关联的属性、方法和事件的元数据;序列化器字段,存储用于将存储在所述创作时字段中的元数据传送到所述活动的声明性表示的数据;商业逻辑字段,存储与存储在所述创作时字段中的元数据相关联的软件代码;以及执行器字段,存储用于执行存储在所述商业逻辑字段中的软件代码的数据,其中,所述语义检查器确认存储在所述商业逻辑字段中的软件代码。8.一种用于对工作流建模的计算机实现的方法,所述工作流包括活动,所述工作流对商业过程建模,所述计算机实现的方法包括呈现多个活动;接收用户对所呈现的活动的选择;以及序列化所接收的选择以创建所述工作流的持久表示。9.如权利要求8所述的计算机实现的方法,其特征在于,还包括提供用于创建与所述工作流相关联的进度表的进度表接口;提供用于创建与所述进度表相关联的作用域的作用域接口;提供用于选择一个或多个活动的活动接口;以及排列所选择的活动,以在所创建的进度表内创建所述工作流,以供在所创建的作用域内执行。10.如权利要求8-9所述的计算机实现的方法,其特征在于,还包括从用户接收表示商业逻辑的软件代码,用于与所述多个活动之一相关联;编译所述软件代码,以创建一个或多个二进制文件;以及执行所创建的二进制文件,以执行所述工作流。11.如权利要求8-10所述的计算机实现的方法,其特征在于,还包括提供用于从与所述多个活动的每一个相关联的组件模型接收所述多个活动的每一个的元数据的元数据接口,所接收的元数据具有语义提供用于通过检查与所接收的元数据相关联的语义来确认所接收的元数据的确认接口;提供用于根据所述确认生成与所接收的元数据相关联的软件代码的代码生成器接口;以及提供用于编译所生成的软件代码的代码编译接口。12.如权利要求8-11所述的计算机实现的方法,其特征在于,还包括编译所排列的活动,以创建可执行工作流;以及按照所创建的进度表并且在所创建的作用域内执行所创建的工作流。13.如权利要求8-12所述的计算机实现的方法,其特征在于,还包括下列的一个或多个将所序列化的工作流表示和软件代码编译成包含所述工作流的可执行表示的单个程序集。提供所述组件模型,用于与每个所排列的活动相关联,所述组件模型定义所排列的活动的属性,以及将所序列化的工作流表示转换成另一工作流语言。14.如权利要求8-13所述的计算机实现的方法,其特征在于,还包括从用户接收用户定义的活动,所述用户定义的活动具有一个或多个与其相关联的语义;评估所述语义,以找出与预定义接口要求的一致性;以及根据所述评估呈现所述用户定义的活动,作为所述多个活动之一。15.如权利要求8-14所述的计算机实现的方法,其特征在于,提供所述多个活动包括下列的一个或多个呈现所述多个活动,其每一个具有一个或多个与其相关联的属性,所述属性指定设计时、编译时和运行时行为;以及可视地向用户呈现所述多个活动;16.如权利要求8-15所述的计算机实现的方法,其特征在于,还包括从用户接收所选择的活动的分层组织,并且其中,所接收的分层组织包括下列的一个或多个事件—条件—动作工作流、结构化工作流、以及约束驱动工作流。17.一个或多个具有用于对工作流建模的计算机可执行组件的计算机可读介质,所述工作流包括活动,所述工作流对商业过程建模,所述计算机可执行组件包括用于呈现多个活动的选项板组件(402);用于从用户接收对由所述选项板组件(402)呈现的活动的选择和分层组织的接口组件(404);以及用于序列化由所述接口组件(404)接收的活动以创建所述工作流的持久表示的声明性组件(406)。18.如权利要求17所述的计算机可读介质,其特征在于,所述接口组件(404)还从用户接收表示商业逻辑的软件代码,用于与所述多个活动之一相关联,并且所述计算机可执行组件还包括运行时组件(408),用于将所述由声明性组件(406)序列化的工作流表示和由所述接口组件(404)接收的软件代码编译成包含工作流的可执行表示的单个程序集。19.如权利要求17-18所述的计算机可读介质,其特征在于,所述声明性组件(406)还将所序列化的活动映射到可扩展模式定义名字空间以供确认。20.如权利要求17-19所述的计算机可读介质,其特征在于,还包括将所述选项板组件(402)、接口组件(404)和声明性组件(406)主宿在应用程序中。全文摘要构建一组件化的工作流模型。工作流的每一步骤被建模为具有元数据的活动,该元数据描述该工作流步骤的设计时方面、编译时方面以及运行时方面。用户通过用户界面或应用程序编程接口选择并安排活动来创建工作流。收集与工作流中每一活动相关联的元数据来创建工作流的持久表示。用户通过创作自定义活动来扩展工作流模型。该工作流可被编译和执行。文档编号G06F17/30GK1755721SQ200510103658公开日2006年4月5日申请日期2005年9月1日优先权日2004年10月1日发明者D·K·舒克拉,A·V·帕拉斯尼斯,A·J·萨加,K·P·瓦莱格瑞普拉,M·梅达,R·B·施密特,A·G·班达卡申请人:微软公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1