本文介绍如何创建长时间运行的工作流服务,此类服务可以长时间运行。 在某一时刻,工作流可能会转入空闲状态,等待附加信息。 当这种情况发生时,工作流将保存到 SQL 数据库并从内存中删除。 当附加信息变得可用时,工作流实例将重新加载回内存,继续执行。
在此方案中,你将实施一个简化的订单系统。 客户端向工作流服务发送初始消息以启动订单。 此服务将订单 ID 返回给客户端。 此时,工作流服务要等待来自客户端的另一条消息,它转入空闲状态并保存到 SQL Server 数据库。 当客户端发送下一条消息订购项目时,工作流服务将重新加载回内存,完成处理此订单。
在代码示例中,它将返回一个字符串,指示项目已添加到订单中。 代码示例并不是技术的现实应用,而是作为一个简单的示例来说明长时间运行的工作流服务。
先决条件
您必须安装了下列软件才能使用本演练:
- Microsoft SQL Server 2008
- Visual Studio 2012
- Microsoft .NET Framework 4.6.1
你还必须熟悉 WCF 和 Visual Studio 2012,并了解如何创建项目/解决方案。
设置 SQL 数据库
为了使工作流服务实例能够持久化,您必须安装 Microsoft SQL Server,并配置一个数据库来存储持久化工作流实例。 单击“开始”按钮并依次选择“所有程序”、“Microsoft SQL Server 2008”和“SQL Server Management Studio”,以运行 Microsoft SQL Management Studio。
单击“连接”按钮登录到 SQL Server 实例
在树视图中右键单击“数据库”并选择“新建数据库”,以创建名为
SQLPersistenceStore
的新数据库。在 SQLPersistenceStore 数据库上运行位于 C:\Windows\Microsoft.NET\Framework\v4.0\SQL\en 目录中的 SqlWorkflowInstanceStoreSchema.sql 脚本文件,以设置所需的数据库架构。
在 SQLPersistenceStore 数据库上运行位于 C:\Windows\Microsoft.NET\Framework\v4.0\SQL\en 目录中的 SqlWorkflowInstanceStoreLogic.sql 脚本文件,以设置所需的数据库逻辑。
创建 Web 承载的工作流服务
创建一个空的 Visual Studio 2012 解决方案并将其命名为
OrderProcessing
。向该解决方案添加一个名为
OrderService
的新 WCF 工作流服务应用程序项目。在项目属性对话框中,选择“Web”选项卡。
在“启动操作”下,选择“特定页”并指定 。
在“服务器”下,选择“使用本地 IIS Web 服务器”。
警告
必须以管理员模式运行 Visual Studio 2012 才能完成此项设置。
这两个步骤将工作流服务项目配置为由 IIS 承载。
如果
Service1.xamlx
尚未打开,请将它打开,并删除现有的“ReceiveRequest”和“SendResponse”活动。选择“顺序服务”活动,单击“变量”链接,然后添加下图中显示的变量。 通过执行此操作,会添加一些稍后将在工作流服务中使用的变量。
注意
如果 CorrelationHandle 不在“变量类型”下拉列表中,请在该下拉列表中选择“浏览类型”。 在“类型名称”框中键入“CorrelationHandle”,从列表框中选择“CorrelationHandle”,然后单击“确定”。
将“ReceiveAndSendReply”活动模板拖放到“顺序服务”活动中。 这组活动将接收来自客户端的消息,并发送回复。
选择“Receive”活动,并设置下图中突出显示的属性。
DisplayName 属性设置在设计器中显示的 Receive 活动的名称。 ServiceContractName 和 OperationName 属性指定 Receive 活动实现的服务协定和操作的名称。 有关如何在工作流服务中使用协定的详细信息,请参阅在工作流中使用协定。
单击“ReceiveStartOrder”活动中的“定义”链接,并设置下图中显示的属性。 请注意,“参数”单选按钮处于选中状态,名为 的参数已绑定到
p_customerName
变量。 这会将“Receive”活动配置为接收某些数据,并将这些数据绑定到局部变量。选择“SendReplyToReceive”活动,并设置下图中突出显示的属性。
单击“SendReplyToStartOrder”活动中的“定义”链接,并设置下图中显示的属性。 请注意,“参数”单选按钮处于选中状态;名为 的参数已绑定到
p_orderId
变量。 此设置指定 SendReplyToStartOrder 活动将类型字符串的值返回给调用方。将“Assign”活动拖放到“Receive”与“SendReply”活动之间,并设置下图中显示的属性:
这将创建一个新的订单 ID,并将该值放在 orderId 变量中。
选择“ReplyToStartOrder”活动。 在属性窗口中,单击“CorrelationInitializers”对应的省略号按钮。 选择“添加初始值设定项”链接,在“初始值设定项”文本框中输入 ,为“相关性类型”选择“查询相关性初始值设定项”,并在“XPATH 查询”下拉框中选择“p_orderId”。 这些设置如下图所示。 单击“确定”。 这将初始化客户端与此工作流服务实例之间的相关性。 当接收到包含此订单 ID 的消息时,将该消息路由至此工作流服务实例。
将另一个“ReceiveAndSendReply”活动拖放到工作流的结尾(在包含第一个“Receive”和“SendReply”活动的“序列”外部)。 这将接收客户端发送的第二条消息,并对它做出响应。
选择包含新添加的“Receive”和“SendReply”活动的“序列”,然后单击“变量”按钮。 添加下图中突出显示的变量:
此外,在
orderResult
范围内添加“字符串”类型的 。选择“Receive”活动,并设置下图中显示的属性:
注意
请不要忘记使用 更改“ServiceContractName”字段。
单击“ReceiveAddItem”活动中的“定义”链接,并添加下图中显示的参数:将 receive 活动配置为接受两个参数,即订单 ID 和订购项目的 ID。
单击“CorrelateOn”省略号按钮并输入 。 在“XPath 查询”下,单击下拉箭头并选择 。 这将对第二个接收活动配置相关性。 有关相关性的详细信息,请参阅相关性。
将“If”活动拖放至紧靠“ReceiveAddItem”活动之后的位置。 此活动的行为与 if 语句类似。
将“Condition”属性设置为
将一个“Assign”活动拖放到“Then”部分,将另一个拖放到“Else”部分,并设置“Assign”活动的属性,如下图所示。
如果条件为
true
,则执行“Then”部分。 如果条件为false
,则执行“Else”部分。选择“SendReplyToReceive”活动,并设置下图中显示的“DisplayName”属性。
单击“SetReplyToAddItem”活动中的“定义”链接并进行配置,如下图所示。 这会将“SendReplyToAddItem”活动配置为在 变量中返回值。
打开 web.config 文件,在 <behavior> 部分添加以下元素以启用工作流持久性。 (确保完成连接字符串。)
<sqlWorkflowInstanceStore connectionString="...;Asynchronous Processing=True" instanceEncodingOption="None" instanceCompletionAction="DeleteAll" instanceLockedExceptionAction="BasicRetry" hostLockRenewalPeriod="00:00:30" runnableInstancesDetectionPeriod="00:00:02" /> <workflowIdle timeToUnload="0"/>
生成解决方案。
创建客户端应用程序以调用工作流服务
将一个名为
OrderClient
的新控制台应用程序项目添加到解决方案中。向
OrderClient
项目中添加对以下程序集的引用:System.ServiceModel.dll
System.ServiceModel.Activities.dll
添加对工作流服务的服务引用,并将
OrderService
指定为命名空间。在客户端项目的
Main()
方法中,添加以下代码:static void Main(string[] args) { // Send initial message to start the workflow service Console.WriteLine("Sending start message"); StartOrderClient startProxy = new StartOrderClient(); string orderId = startProxy.StartOrder("Kim Abercrombie"); // The workflow service is now waiting for the second message to be sent Console.WriteLine("Workflow service is idle..."); Console.WriteLine("Press [ENTER] to send an add item message to reactivate the workflow service..."); Console.ReadLine(); // Send the second message Console.WriteLine("Sending add item message"); AddItemClient addProxy = new AddItemClient(); AddItem item = new AddItem(); item.p_itemId = "Zune HD"; item.p_orderId = orderId; string orderResult = addProxy.AddItem(item); Console.WriteLine("Service returned: " + orderResult); }
生成解决方案,并运行
OrderClient
应用程序。 客户端将显示以下文本:Sending start messageWorkflow service is idle...Press [ENTER] to send an add item message to reactivate the workflow service...
若要验证工作流服务是否已持久化,请转到“开始”菜单,并依次选择“所有程序”、“Microsoft SQL Server 2008”、“SQL Server Management Studio”来启动 SQL Server Management Studio。
- 在左侧窗格中,依次展开“数据库”、“SQLPersistenceStore”、“视图”,右键单击“System.Activities.DurableInstancing.Instances”并选择“选择前 1000 行”。 在“结果”窗格中,确认至少列出了一个实例。 如果运行时出现异常,则可能存在先前运行的其他实例。 可通过以下方式删除现有行:右键单击“System.Activities.DurableInstancing.Instances”,选择“编辑前 200 行”,按“执行”按钮,选择结果窗格中的所有行,然后选择“删除”。 若要验证数据库中显示的实例是否为应用程序创建的实例,请在运行客户端之前验证实例视图是否为空。 客户端开始运行后,重新运行查询(选择前 1000 行),并确认已添加新实例。
按 Enter 将添加项目消息发送至工作流服务。 客户端将显示以下文本:
Sending add item messageService returned: Item added to orderPress any key to continue . . .