!
简介
本文包含世界s最琐碎无用的Windows Workflow Foundation(WF)的应用程序,以及一些WF本身的背景。该软件的怪胎秀的目的是揭露WF新人如何与NET 3.0这个令人兴奋的新的部分开始的基本知识。它没有得到任何复杂的情况下,当然不包含任何WF的最佳做法。它只是告诉你如何把一个最小的WF的应用程序。如果你有更现实的需要和要求,您可以使用此代码作为一个真正的发展的出发地点。
,我会承认这里(纽约市),现在(2006年11月),我绝不是一个WF的专家。我m关于永丰,真的非常兴奋,并一直在阅读关于它在我的空闲时间玩了。本文纯粹是书面的兴奋的技术,所以我希望,兴奋眼前一亮,有助于让你兴奋过。
在这篇文章中所示的应用程序是一个优秀图书开始使用演示应用程序的突变绋基要的Windows Workflow Foundation的?佛法舒克拉和鲍勃施密特。我极力推荐这本书,如果你想获得认真地学习WF。您可能还需要检查MSDN上由Don Box和佛法舒克拉。
,跆拳道是WF的?
在我们进入建设WF应用程序,让锟s花点时间掌握背后WF的总体思路。 WF Windows Workflow Foundation的代表。这是一个子系统,它提供了一个用于创建和执行基于工作流的应用程序运行时的。NET Framework 3.0。锟s漂亮的营销潺潺,但究竟是什么意思?好问题??/ P>
从一个非常高层次的角度来看,WF允许您创建程序可以保存到后备存储时,他们无效,然后在必要时恢复。你可以声明一个基于XML的语言被称为扩展应用程序标记语言(XAML)的总体方案流和负载/您的XAML工作流在运行时执行。表示你的应用程序锟s在一种标记语言的一般逻辑流程简化了开发过程很大,特别是因为它在创建软件的图形设计工具的使用打开了新的可能性。我为什么会使用WF?
许多应用程序的性质反应。他们围坐在一起的时间无限期等待期间发生的事情(也许是在某个目录中创建的文件)。当外部刺激到应用程序获取忙于处理传入的数据。与这种常见的情况问题是性能和可扩展性有很大影响的事实,而应用程序是等待外部输入,它消耗的处理时间从任何线程上运行。
WF提供了一个解决该问题。由于在WF工作流作为一个对象树表示,支持序列化/反序列化这些对象,WF的工作流内置支持保存到从数据库加载。我不锟t的意思,只是由应用程序操纵的数据保存,我的意思是,program本身是保存??。
应用程序的状态是有效立蔷薇??和低温冷冻投入,可以这么说。当谈到时间,恢复工作流处理(即外部刺激到达)锟绔蔷薇??工作流程是解冻,并继续正常执行。请记住,工作流可以在不同的计算机恢复,千里之遥,从那里被冻结,15个月后。这在性能和可扩展性方面带来了巨大的收益,因为工作流程是不绑定到一个特定的线程,进程,甚至电脑。
锟s我锟m要对WF提供的介绍材料。我没锟t解释几乎所有的WF是所有关于。如果你有兴趣在WF的更彻底,更周到的解释,我建议你读了这本书前面提到的(锟绋基要的Windows Workflow Foundation的??现在,让我们锟s发挥一些WF代码
世界锟s愚蠢的WF的应用
应用程序的I锟m这里呈现给你问他/她的名字的用户,等待用户键入它在,然后打印锟绐ello,用户名!??到控制台。很明显,这个应用程序是唯一感兴趣的,因为它使用Windows Workflow Foundation来执行它的魔力。我试图保持尽可能简单和最小的WF的使用,只是让锟s容易看到如何设立一个应用程序使用WF的。
有参与此应用程序的两个组件:FirstWFLibrary.DLL??该程序集包含用于执行打印输出到控制台任务,并获得用户锟s名称的自定义WF活动。FirstWFApp.EXE??这个大会是一个控制台应用程序加载WF WorkflowRuntime的活动,并提出在FirstWFLibrary使用。
的两个组件中的每一个都包含两片的拼图:
FirstWFLibrary.DLL自定义活动??在WF工作流工作的基本单位是一个"活动"。 WF的应用程序中的所有自定义活动Activity基类派生并重写其受保护的执行方法,以提供自己的执行逻辑。命名空间映射??为了能够在XAML中使用自定义活动,我们需要提供一种方式来告诉XAML分析器在这些阶级存在的命名空间(S)。这是通过应用属性大会,我们稍后将看到的。
FirstWFApp.EXE工作流宣言"吗?在这个应用程序?工作流程需要阅读的使用者锟s名称和显示回给他/她是在XAML中表示。在本次大会的XAML文件使用FirstWFLibrary大会宣布自定义活动。请注意,它不要求工作流在XAML中声明。宣布他们在其他格式,如C#代码,这是完全可能。我选择了在XAML中的工作流程,因为它锟s更有趣的方式来表达对这个应用程序。 :)工作流运行时主机??的最后一块拼图是一个类加载WF运行时,配置它,然后告诉它开始运行。在此应用程序的EntryPoint类需要护理这项工作。
本文的其余部分检查上面列出的应用程序的每个部分。自定义活动
如前所述,此演示应用程序有三个任务来执行。首先,它必须显示在控制台窗口中,要求他/她的名字的用户的消息。然后,它必须等待用户输入他们的姓名,然后按Enter。最后,它显示另一条消息给用户,其中包括他们的名字。
这些任务都表示为一个单独的活动派生类。这些类的实例将执行实际工作所必需的程序执行。首先,让我们锟s初始提示是如何显示到控制台/ / /公升; summarygt;/ / /要求用户提供他们的姓名。/ / / summarygt;公共类PromptForUserName:活动{ 保护覆盖ActivityExecutionStatus执行(
; ActivityExecutionContext的ExecutionContext) { Console.Write("请输入您的姓名,然后按Enter:"); 返回ActivityExecutionStatus.Closed; }}
这个类是完美示范了如何创建一个可以包含在WF工作流的活动。它从System.Workflow.ComponentModel.Activity类继承并覆盖Execute方法来提供自定义活动执行逻辑。由于这项活动是逻辑上完成后,写一条消息到控制台的,它返回ActivityExecutionStatus.Closed告知这是WF运行时。
你可能会奇怪,为什么一个活动会从Execute方法返回,如果还没有完成执行。还记得前面对我提到,WF的工作流可以passivated??,并存储在数据库中,直到它需要继续执行?那么,活动锟sExecute方法将返回ActivityExecutionStatus.Executing如果它不能完成直到最终到达外部输入。
事实上,世界下一步锟s愚蠢的WF的应用需要一个时间的推移,才可以继续处理无限期。这可能需要用户3秒或3天类型在他/她的名字。在这段时间内的工作流程将没有处理。如果这是一个不太愚蠢WF的应用程序,我们可能会决定钝化的工作流程,直到用户名终于来临,在这一点,我们将恢复工作流程,让它继续。我们锟r个人不这样做,在这里,但这个活动显示如何设置一个bookmark使WF运行时可以通知活动时,输入已经抵达
/ / /公升;??summarygt;/ / /代表阅读的文本一行从控制台的活动。/ / / summarygt;公共类ReadConsoleLine:活动{ #地区的inputText物业
160;私人字符串的inputText; 公共字符串的inputText { 得到{this.inputText;} } #endregion / / inputText的物业 #地区执行[覆盖] 保护覆盖ActivityExecutionStatus执行( ActivityExecutionContext的ExecutionContext) {
60; / /创建一个WorkflowQueue,这使得这项活动quot; bookmarkquot; / /它应该继续执行,一旦外部输入到达 / /(在这种情况下,从控制台读取字符串)。 WorkflowQueue workflowQueue = this.GetWorkflowQueue(的ExecutionContext); / /将一个处理程序,处理外部输入。 workflowQueue.QueueItemAvailable = ProcessQueueItemAvailable; &
#160;/ /附加清理后输入已处理的处理程序。 workflowQueue.QueueItemAvailable = CloseActivity; / /工作流运行时表示,这一活动是在逻辑上仍然 / /执行,即使它不会做任何事情,直到输入到达。 返回ActivityExecutionStatus.Executing; } #endregion / /执行[覆盖]
#地区的事件处理程序 无效ProcessQueueItemAvailable(对象发件人,QueueEventArgs发送) { / /外部输入已经来临,所以唤醒并处理它。 WorkflowQueue workflowQueue = this.GetWorkflowQueue( 发件人为ActivityExecutionContext);
如果(workflowQueue.Count GT; 0) this.inputText = workflowQueue.Dequeue()作为字符串; } 无效CloseActivity(对象发件人,QueueEventArgs发送) { / /外部输入已经到来,经过处理,所以扔掉 / / WorkflowQueue我们,并告诉WF运行时活动结束。 ActivityExecutionContext的ExecutionContext = 发件人,ActivityExecutionContext; WorkflowQueuingService queuingService = executionContext.GetServicelt; WorkflowQueuingServicegt;();
0;queuingService.DeleteWorkflowQueue(this.Name); executionContext.CloseActivity(); } #endregion / /事件处理程序
#地区的私人助手 / /辅助性方法,该方法返回一个WorkflowQueue。 WorkflowQueue GetWorkflowQueue(ActivityExecutionContext的ExecutionContext) { WorkflowQueue队列; WorkflowQueuingService queuingService = executionContext.GetServicelt; WorkflowQueuingServicegt;(); 如果(queuingService.Exists(this.Name)) 队列= queuingService.GetWorkflowQueue(this.Name); 其他 队列= queuingService.CreateWorkflowQueue(this.Name,真正); 返回队列; } #endregion / /私人佣工}
在ReadConsoleLine锟sExecute方法"锟bookmark??是建立和方法立即返回控制权交还给WF运行时。但是,它的回报??代码>执行??让WF运行时知道它不应该去处理任何其他活动。当用户输入的最后到达,ReadConsoleLine锟sProcessQueueItemAvailable和CloseActivity事件处理方法将被调用。这些方法的第一个用户锟s名称存储在一个私有变量。另一种方法是清理和关闭的活动,使WF运行时可以继续处理其他活动。
最后一个活动是负责打印出问候用户与他/她的名字,。这个活动有一个依赖项属性称为用户名。正如我们稍后将看到,这个属性绑定到ReadConsoleLine活动收到的输入值。数据绑定是建立在这些对象的XAML声明。我们l升该很快,但现在让我们锟s看到GreetUser活动/ / /公升。summarygt;/ / /打印用户的问候。/ / / summarygt;公共类GreetUser:活动{ 公共静态只读的DependencyProperty UserNameProperty; 静态GreetUser() { UserNameProperty = DependencyProperty.Register的( "UserNamequot; typeof运算(字符串), typeof运算(GreetUser)); } / /用户名是一个依赖项属性,因此它可以绑定到 / / ReadConsoleLine活动的inputText属性。 公共字符串的用户名 { {返回(字符串)的GetValue(UserNameProperty);} 集合{的SetValue(UserNameProperty,价值);} } 保护覆盖ActivityExecutionStatus执行(
160; ActivityExecutionContext的ExecutionContext) { 字符串的问候= String.Format("您好,{0} quot;,this.UserName); Console.WriteLine(贺卡); 返回ActivityExecutionStatus.Closed; }}命名空间映射
为了使用我们的自定义在XAML中的活动,我们需要提供的XAML解析器的方式来知道什么CLR命名空间的类居住,因为XAML是一种XML语言,我们需要提供关联的CLR任意XML命名空间(基本上,一个URI)命名空间。这是可以做到在任何项目中的代码文件,但我只是为了传统的AssemblyInfo.cs创建。这里s该文件的内容:使用System.Workflow.ComponentModel.Serialization;/ /这个属性使得它可以在XAML中使用自定义活动。[大会:XmlnsDefinition(quot; http://FirstWFLibraryquot;,"FirstWFLibraryquot;)]工作流宣言"
现在,我们需要执行我们的程序逻辑的自定义活动,其命名空间映射,我们可以创建这些类型的实例。在本演示中,我们将在XAML中创建它们。看作只是一个通用的对象实例化的标记语言XAML的。它允许你配置的对象和表达它们之间的层次关系,很容易。
这里是世界的XAML声明锟s愚蠢的工作流程:
LT; WF:SequenceActivity XMLNS ="; http://FirstWFLibraryquot"; 的xmlns:X ="; http://schemas.microsoft.com/winfx/2006/xamlquot"; XMLNS:WF ="; http://schemas.microsoft.com/winfx/2006/xaml/workflowquot"; GT;
0; LT; PromptForUserName / GT; LT; ReadConsoleLine x:名称="; getUserNamequot / GT; LT; GreetUser用户名="{WF:ActivityBind名称= getUserName,路径的inputText}"/ GT;LT; / WF:SequenceActivitygt;
在工作流的根活动是一个SequenceActivity对象,这是在WF框架提供了一个类。这是一个CompositeActivity派生类,在他们被声明的顺序执行其子活动,只执行一个子活动完成后,以前的儿童活动。
根活动中包含的XML命名空间映射。默认XML命名空间映射到在上一节中的文章XmlnsDefinition属性指定的URI。这使我们可以参考我们的自定义活动类型没有任何命名空间前缀。
的另一个兴趣点是ReadConsoleLine GreetUser活动之间的关系。后者的UserName属性绑定到前的inputText财产。这种绑定允许从一个活动转移到另一个控制台中键入的文本。一个属性,是一项有约束力的的目标,它必须是一个"依赖项属性。"正如我们在"自定义活动"一节中所看到的,是多一点,比只是一个普通的属性创建一个依赖项属性的代码,但相依性属性,可以在使用方式,不能正常属性。你可以阅读有关SDK中的这些差异,如果你关心。工作流运行时主机
您可以承载多种方式WF运行时,但这个演示只是使用一个普通的香草控制台应用程序。有几个步骤,您必须遵循以获得WF运行时,运行在您的AppDomain。下面的方法是世界s愚蠢的WF的应用程序主机WF运行时(这种方法,当然是在一个类中,):
公共静态无效的主要(){ / /创建一个WorkflowRuntime实例,将执行和协调 / /我们的工作流程的所有活动。 (WorkflowRuntime的WorkflowRuntime的新的WorkflowRuntime()) {
0;/ /告诉工作流运行时,在哪里可以找到我们的自定义活动类型。&
#160; TypeProvider typeProvider =新TypeProvider(WorkflowRuntime的); typeProvider.AddAssemblyReference("FirstWFLibrary.dllquot;); workflowRuntime.AddService(typeProvider);
; / /激活工作流运行时。 workflowRuntime.StartRuntime(); / /加载的XAML文件,其中包含了我们的简单的工作流的宣言 / /创建它的一个实例。一旦它被加载,启动工作流 / /所以,在它的活动会执行。 WorkflowInstance workflowInstance; (XmlTextReader的XmlReader的=
新的XmlTextReader的(@ quot; .. \ .. \ HelloUserWorkflow.xamlquot;)) { workflowInstance = workflowRuntime.CreateWorkflow(XmlReader的); workflowInstance.Start();
60;} / / ReadConsoleLine活动使用quot; bookmarkquot;表明,它必须 / /等待外部输入,才可以完成。在这种情况下, / /外部输入到控制台窗口中输入用户的名称。 字符串的用户名=(); workflowInstance.EnqueueItem("; getUserNamequot",用户名,NULL,NULL); / /暂停,使这里的工作流程可以显示的问候语。
(); / /拆毁所有的工作流程服务和运行时。 / /(这可能是多余的,因为"运行"对象是在 / /使用的块)。 workflowRuntime.StopRuntime(); }}
我锟m不会解释该方法行线,因为它的评论不够好。一点利益,我会提的是,一旦WorkflowInstance启动时,该方法然后调用Console.ReadLine用户锟s名称。一旦检索的名称是,它摆上锟绞etUserName??流队列ReadConsoleLine活动,这是创建的。这是一个提供的工作流程,使其恢复处理外部输入的例子。一旦用户s名称到工作流队列,ReadConsoleLine活动将有回调方法调用,它可以执行完。结论
本文展示了如何创建一个应用程序使用Windows Workflow Foundation的。希望它让你感觉像世界锟s愚蠢的WF的应用值得它的名字,也是您了解WF的基本知识,以及如何在应用程序中使用它。
正如我前面提到的,这个应用程序没有在所有需要使用WF的权力,但它确实传达所涉及的基本概念。它显示了如何WF工作流的活动树,如何将这些活动可以使用锟bookmarks的概念??表示应继续处理外部刺激发生后,工作流可以在XAML中声明,以及如何主机WF的工作流运行时。一路上,我提到WF的工作流可以钝化和恢复,它提供了一个强有力的手段改善应用程序的锟s可扩展性和性能。