附录 A:开发订单应用程序
此附录为开发人员提供了构建 Contoso 订单服务所需的详细步骤。此附录的目的是使开发人员熟悉如何通过使用 Visual Studio 2010 和 .NET Framework 4 开发应用程序(包括 Windows Communication Foundation (WCF) 和/或 Windows Workflow Foundation (WF) 服务)。本教程的主要部分使用此应用程序向系统管理员或应用程序所有者介绍如何使用 Windows Server AppFabric 来部署、监控应用程序(包括 WCF 和/或 WF 服务)并对其进行疑难解答。
此 Contoso 订单服务由以下四个应用程序组成:
订单处理服务: 一种模拟通过 Web 服务界面调用现有订单处理应用程序的 WCF 服务。
发售服务: 一种模拟通过 API 调用现有发售应用程序的 WCF 服务。
订单工作流服务: 一种用于管理订单流程(包括接收订单、处理订单和发售订单)的 WF 工作流服务。
订单客户端: 一种用作订单服务前端的 Windows 窗体应用程序。
备注
该附录不要求您安装 Windows Server AppFabric。但是您必须首先安装 Windows Server AppFabric 界面的使用教程文件以创建正确的文件结构,该附录才能正确生成。请注意,该附录不要求您首先完成 Windows Server AppFabric 界面的使用教程教程 - 只是安装这些文件。有关 Windows Server AppFabric 界面的使用教程教程的安装过程,请参阅第 1 课:入门。C:\DublinTutorial\OrderServiceSolution\Completed 文件夹中包含已完成解决方案的副本。
过程
您将通过完成以下步骤来创建该应用程序:
开发订单处理 WCF 服务
开发发售 WCF 服务
开发订单工作流 WF 服务
完成订单处理 WCF 服务
完成 WCF 服务的发售
开发订单客户端应用程序
将订单服务打包
开发订单处理 WCF 服务
订单处理应用程序是一个 Contoso 购买的应用程序。它提供了其他应用程序可以与之通信的 Web 服务。作为一名 Contoso 开发人员,您需要开发一个名为 OrderProcessingService 的 WCF 服务,以与订单处理应用程序交互。
为 OrderProcessingService 创建 Visual Studio 解决方案和 WCF 服务应用程序的步骤
单击「开始」,依次指向“所有程序”、“Microsoft Visual Studio 2010”,然后单击“Microsoft Visual Studio 2010”。
从“文件”菜单中,单击“新建”,然后单击“新建项目”。
从“新建项目”中,选择或键入以下值,然后单击“确定”。
属性 值 项目类型
Visual C#/Web
模板
WCF 服务应用程序
名称
OrderProcessingService
位置
C:\DublinTutorial\OrderServiceSolution
解决方案名称
OrderService
为解决方案创建目录
(已选择)
在“解决方案资源管理器”中,展开“OrderProcessingService”,右键单击“IService1.cs”,然后单击“删除”。
单击“确定”确认永久删除此文件。
在“解决方案资源管理器”中,展开“OrderProcessingService”,右键单击“Service1.svc”,然后单击“删除”。
单击“确定”确认永久删除此文件。
创建 WCF 服务的第一个任务是定义协定。协定中指定服务支持的操作。操作可以看作是 Web 服务方法。接口中的每个方法都对应一个特定的服务操作。在 OrderProcessingService 中,您将定义以下两个方法:ProcessOrder 和 CancelOrderProcess。
为订单处理服务定义服务协定和数据协定的步骤
在“解决方案资源管理器”中,右键单击“OrderProcessService”,指向“添加”,然后单击“新项目”。
从“添加新项目 - OrderProcessService”中,选择或键入以下值,然后单击“添加”。
属性 值 类别
Visual C#/Web
模板
WCF 服务
名称
OrderProcessing.svc
已将以下两个文件添加到此解决方案:IOrderProcessing.cs 和 OrderProcessing.svc。
在“解决方案资源管理器”中,双击“IOrderProcessing.cs”将其打开。
右键单击“OrderProcessingService”命名空间,单击“重构”,然后单击“重命名”打开“重命名”对话框。
在“新名称”中,键入“Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService”,然后单击“确定”。
单击“应用”,然后单击“是”。
修改 OrderProcessing.svc 源代码,使它看起来类似于如下所示:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService { [ServiceContract] public interface IOrderProcessing { [OperationContract] string ProcessOrder(PurchaseOrder po); [OperationContract] string CancelOrderProcess(string orderID); } [DataContract] public class PurchaseOrder { [DataMember] public string POID; [DataMember] public string FirstName; [DataMember] public string LastName; [DataMember] public string EmailAddress; [DataMember] public string TelephoneNumber; [DataMember] public string AddressLine1; [DataMember] public string AddressLine2; [DataMember] public string City; [DataMember] public string State; [DataMember] public string ZipCode; [DataMember] public string Description; [DataMember] public int Quantity; [DataMember] public string UnitPrice; } }
在此文件中,您将定义数据协定和服务协定。客户端可以调用服务来处理订单及取消订单处理。
在您创建协定(通过使用接口定义)之后,下一步是实现该接口。此操作包括创建名为 OrderProcessService 的类,用于实现用户定义的 IOrderProcessing 接口。
实现订单处理服务协定的步骤
在“解决方案资源管理器”中,双击“IOrderProcessing.cs”将其打开。
修改源代码,使它看起来类似于如下所示:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; using System.Threading; using System.IO; namespace Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService { class WorkItem { private Thread workThread; private object workItemLock; private bool completeFlag; public Thread WorkThread { get { return workThread; } set { workThread = value; } } public object WorkItemLock { get { return workItemLock; } } public bool CompleteFlag { get { return completeFlag; } } public WorkItem(Thread WorkThread) { workThread = WorkThread; workItemLock = new object(); completeFlag = false; } public void Complete() { completeFlag = true; } } public class OrderProcessing : IOrderProcessing { private static Dictionary<String, WorkItem> WorkItemMap = new Dictionary<String, WorkItem>(); public string ProcessOrder(PurchaseOrder po) { //run the code from a different thread to simulate asynchronized call ThreadPool.QueueUserWorkItem(SendProcessResult, po); return ("The request for processing order[" + po.POID + "] has been received."); } private void SendProcessResult(object state) { PurchaseOrder po = (PurchaseOrder)state; WorkItem workItem = new WorkItem(Thread.CurrentThread); WorkItemMap.Add(po.POID, workItem); //Simulating the order processing process Thread.Sleep(120000); //The following code will be uncommented later in the process //OrderWorkflowService.ProcessServiceResult reply = new OrderWorkflowService.ProcessServiceResult(); //reply.POID = po.POID; //reply.Message = "The order has been processed successfully."; //lock (workItem.WorkItemLock) //{ // using (OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient client = new OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient()) // { // client.SubmitProcessResult(reply); // } // workItem.Complete(); // WorkItemMap.Remove(po.POID); //} } public string CancelOrderProcess(string poID) { string ret = "Cancel unavailable for this order."; //=====================================================// //===[ Attempt to get a work item for the order Id //=====================================================// WorkItem workItem; if (WorkItemMap.TryGetValue(poID, out workItem) == true) { //=========================================================== //=== Slight race condition here. Workitem could complete //=== before we aquire its lock. So we check the //=== completion flag inside the lock. //=========================================================== lock (workItem.WorkItemLock) { if ((!workItem.CompleteFlag) && (workItem.WorkThread.IsAlive)) { workItem.WorkThread.Abort(); WorkItemMap.Remove(poID); ret = "The order process has been terminated successfully."; } } } return ret; } } }
使用配置文件可以使您在部署时(而不是设计时)灵活地提供终结点和服务行为数据。在此配置文件中,您将定义两个终结点。
使用配置文件配置订单处理服务的步骤
在“解决方案资源管理器”中,展开“OrderProcessingService”,然后双击“Web.config”将其打开。在 <system.serviceModel> 标记中添加 <services> 标记:
<services> <service name="Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService.OrderProcessing"> <endpoint address="" binding="basicHttpBinding" contract="Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService.IOrderProcessing" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services>
编译订单处理 WCF 服务的步骤
- 在“解决方案资源管理器”中,右键单击“OrderProcessingService”项目,然后单击“重建”。确保此项目在“输出”窗口中成功编译。
测试订单处理 WCF 服务的步骤
在“解决方案资源管理器”中,右键单击“OrderProcessingService”项目,然后单击“在浏览器中查看”。将打开一个 Internet Explorer 窗口,其中列出目录文件。
从 Internet Explorer 窗口中,单击“OrderProcessing.svc”。确保您未遇到任何错误。
开发发售 WCF 服务
发售服务是一种调用 SQL Server 存储的 WCF 服务。在此模拟中,您并不真正地调用数据库。
向此解决方案中添加新 WCF 服务应用程序项目的步骤
在“解决方案资源管理器”中,右键单击“解决方案‘OrderService’”,指向“添加”,然后单击“新项目”。
在“添加新项目”中,选择或键入以下值,然后单击“确定”。
属性 值 项目类型
Visual C#/Web
模板
WCF 服务应用程序
名称
ShippingService
位置
C:\DublinTutorial\OrderServiceSolution\OrderService
在“解决方案资源管理器”中,展开“ShippingService”,右键单击“IService1.cs”,然后单击“删除”。
单击“确定”确认永久删除此文件。
在“解决方案资源管理器”中,展开“ShippingService”,右键单击“Service1.svc”,然后单击“删除”。
单击“确定”确认永久删除此文件。
您将定义一个名为 IShipping 的服务协定,其中包含两个操作协定,即 ShipOrder 和 CancelShipping。
定义发售 WCF 服务协定的步骤
在“解决方案资源管理器”中,右键单击“ShippingService”,指向“添加”,然后单击“新项目”。
在“添加新项目 - ShippingService”中,选择或键入以下值,然后单击“添加”。
属性 值 类别
Visual C#/Web
模板
WCF 服务
名称
Shipping.svc
会将以下两个文件添加到项目中:IShipping.cs 和 Shipping.svc。
在“解决方案资源管理器”中,双击“IShipping.cs”将其打开。
右键单击“ShippingService”命名空间,单击“重构”,然后单击“重命名”以打开“重命名”对话框。
在“新名称”中,键入“Microsoft.Samples.Dublin.Tutorials.OrderService.ShippingService”,然后单击“确定”。
单击“应用”,然后单击“是”。
修改源代码,使它看起来类似于如下所示:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace Microsoft.Samples.Dublin.Tutorials.OrderService.ShippingService { [ServiceContract] public interface IShipping { [OperationContract] string ShipOrder(string poID); [OperationContract] string CancelShipping(string poID); } }
实现发售 WCF 服务协定的步骤
在“解决方案资源管理器”中,双击“Shipping.svc”将其打开。
修改源代码,使它看起来类似于如下所示:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; using System.Threading; namespace Microsoft.Samples.Dublin.Tutorials.OrderService.ShippingService { class WorkItem { private Thread workThread; private object workItemLock; private bool completeFlag; public Thread WorkThread { get { return workThread; } set { workThread = value; } } public object WorkItemLock { get { return workItemLock; } } public bool CompleteFlag { get { return completeFlag; } } public WorkItem(Thread WorkThread) { workThread = WorkThread; workItemLock = new object(); completeFlag = false; } public void Complete() { completeFlag = true; } } public class Shipping : IShipping { private static Dictionary<String, WorkItem> WorkItemMap = new Dictionary<String, WorkItem>(); public string ShipOrder(string poID) { //run the code from a different thread to simulate asynchronized call ThreadPool.QueueUserWorkItem(SendShippingResult, poID); return ("The request for processing order[" + poID + "] has been received."); } private void SendShippingResult(object state) { string poID = state.ToString(); WorkItem workItem = new WorkItem(Thread.CurrentThread); WorkItemMap.Add(poID, workItem); //Simulating the order processing process Thread.Sleep(60000); //The following portion will be uncommented after referencing OrderWorkflowService //OrderWorkflowService.ShippingServiceResult reply = new OrderWorkflowService.ShippingServiceResult(); //reply.POID = poID; //reply.Message = "The order has been shipped."; //lock (workItem.WorkItemLock) //{ // using (OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient client = new OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient()) // { // client.SubmitShippingResult(reply); // } // workItem.Complete(); // WorkItemMap.Remove(poID); //} } public string CancelShipping(string poID) { string ret = "Cancel unavailable for this order."; //=====================================================// //===[ Attempt to get a work item for the order Id //=====================================================// WorkItem workItem; if (WorkItemMap.TryGetValue(poID, out workItem) == true) { //=========================================================== //=== Slight race condition here. Workitem could complete //=== before we aquire its lock. So we check the //=== completion flag inside the lock. //=========================================================== lock (workItem.WorkItemLock) { if ((!workItem.CompleteFlag) && (workItem.WorkThread.IsAlive)) { workItem.WorkThread.Abort(); WorkItemMap.Remove(poID); ret = "The shipping process has been terminated successfully."; } } } return ret; } } }
在此配置文件中,您将定义两个终结点。
使用配置文件配置发售 WCF 服务的步骤
在“解决方案资源管理器”中,展开“ShippingService”,然后双击“Web.config”将其打开。在 <system.serviceModel> 标记中添加 <services> 标记:
<services> <service name="Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService.Shipping"> <endpoint address="" binding="basicHttpBinding" contract="Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService.IShipping" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services>
编译发售 WCF 服务的步骤
- 在“解决方案资源管理器”中,右键单击“ShippingService”项目,然后单击“重建”。确保此项目在“输出”窗口中成功编译。
开发订单工作流 WF 服务
订单工作流服务应用程序是整个服务的主要部分。它用于安排整个业务流程。它接收采购订单,然后调用 OrderProcessingService 和 ShippingService,并最终将关于采购订单状态的电子邮件发送给客户。
向解决方案中添加新 WCF 工作流服务应用程序项目的步骤
在“解决方案资源管理器”中,右键单击“解决方案‘OrderService’”,指向“添加”,然后单击“新项目”。
在“添加新项目”中,选择或键入以下值,然后单击“确定”。
属性 值 项目类型
Visual C#/工作流
模板
WCF 工作流服务应用程序
名称
OrderWorkflowService
位置
C:\DublinTutorial\OrderServiceSolution\OrderService
OrderWorkflowService 使用 OrderProcessingService 和 ShippingService。您必须引用这两个服务。
添加服务引用的步骤
在“解决方案资源管理器”中,右键单击“OrderWorkflowService”,然后单击“添加服务引用”。
在“添加服务引用”中,单击“发现”。Visual Studio 应会发现这两个服务。
输入并选择以下值,然后单击“确定”以创建服务引用。
属性 值 服务
OrderProcessing.svc
命名空间
OrderProcessService
重复这些步骤,以使用以下值来添加其他服务引用:
属性 值 服务
Shipping
命名空间
ShippingService
您需要定义用于模拟发送电子邮件通知的自定义工作流活动。
创建工作流代码活动的步骤
在“解决方案资源管理器”中,右键单击“OrderWorkflowService”,指向“添加”,然后单击“新项目”。
从“添加新项目 - OrderWorkflowService”中,选择或键入以下值,然后单击“添加”。
属性 值 类别
Visual C#/工作流
模板
Code Activity
名称
SendNotification.cs
在“解决方案资源管理器”中,双击“SendNotification.cs”将其打开。
右键单击“OrderWorkflowService”命名空间,单击“重构”,然后单击“重命名”以打开“重命名”对话框。
在**“新名称”**中,键入“Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService”,然后单击“确定”。
单击“应用”,然后单击“是”。
修改源代码,使它看起来类似于如下所示:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Activities; using System.IO; namespace Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService { public class SendNotification : CodeActivity { InArgument<string> to; InArgument<string> subject; InArgument<string> body; string pathRoot = @"C:\DublinTutorial\Inbox\"; public InArgument<string> To { get { return this.to; } set { this.to = value; } } public InArgument<string> Subject { get { return this.subject; } set { this.subject = value; } } public InArgument<string> Body { get { return this.body; } set { this.body = value; } } public SendNotification() { } public SendNotification(InArgument<string> To, InArgument<string> Subject, InArgument<string> Body) { this.to = To; this.subject = Subject; this.body = Body; } protected override void Execute(CodeActivityContext context) { string filename; string content; try { filename = this.to.Get<String>(context) + "~~" + this.subject.Get<string>(context) + "_" + DateTime.Now.ToFileTime() + ".txt"; content = String.Format("To: {0}" + Environment.NewLine + "From: {1}" + Environment.NewLine + "Subject: {2}" + Environment.NewLine + Environment.NewLine + "{3}", this.to.Get<String>(context), "CustomerRelations@Contoso.com", this.subject.Get<String>(context), this.body.Get<String>(context)); File.WriteAllText((pathRoot + filename), content); } catch (Exception Ex) { context.SetValue(Body, Ex.Message); } } } }
请注意,此路径被硬编码为“C:\DublinTutorial\Inbox\”。
在以下过程中,您将定义数据类型。这些数据类型用于 OrderProcessingService 和 ShippingService 将结果发送回 OrderWorkflowService。
定义数据类型的步骤
在“解决方案资源管理器”中,右键单击“OrderWorkflowService”,指向“添加”,然后单击“新项目”。
从“添加新项目 - OrderWorkflowService”中,选择或键入以下值,然后单击“添加”。
属性 值 类别
Visual C#/代码
模板
代码文件
名称
DataTypes.cs
在“解决方案资源管理器”中,双击“DataTypes.cs”将其打开。
修改源代码,使它看起来类似于如下所示:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService { [DataContract] public class ProcessServiceResult { [DataMember] public string POID; [DataMember] public string Message; } [DataContract] public class ShippingServiceResult { [DataMember] public string POID; [DataMember] public string Message; } }
在“解决方案资源管理器”中,右键单击“OrderWorkflowService”,然后单击“重建”。您必须构建项目,以便能够从您将在后续步骤中开发的工作流访问代码活动。编译还可以将引用的 WCF 服务终结点显示给工作流。
下一步是定义工作流。工作流包含几种状态。您先从定义状态开始,然后再定义状态细节。开发过程的每一部分都可以包含以下步骤:
使用活动撰写工作流。
定义变量。
配置活动。
定义工作流的步骤
在“解决方案资源管理器”中,展开“OrderWorkflowService”,右键单击“Service1.xamlx”,然后单击“重命名”。将文件重命名为“OrderWorkflow.xamlx”。
在“解决方案资源管理器”中,双击“OrderWorkflow.xamlx”将其打开。顺序服务中列出了以下两个活动:一个名为 ReceiveRequest,另一个名为 SendResponse。
右键单击“顺序服务”活动,然后单击“删除”。
在工作流中,单击“将活动放在此处”,然后在“属性”面板中设置以下值。
属性 值 configurationName
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderWorkflow
名称
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderWorkflow
单击窗口左侧的“工具箱”打开“工具箱”面板,然后将其固定在窗口左侧。
将以下活动从工具箱拖动到显示“将活动放在此处”的工作流中。
类别 活动 注意 流程图
流程图
默认情况下,流程图活动是包含“开始”的复合活动。您将在以下步骤中向其中添加更多活动。
将以下活动按显示顺序从工具箱拖动到工作流:
类别 活动 注意 消息
ReceiveAndSendReply
这是“等待订单”状态。
控制流
Sequence
这将包含第二个状态“订单已打开”。
流程图
FlowDecision
FlowDecision 活动帮助在状态之间转换。
控制流
Sequence
这将包含第三个状态“订单已处理”。
流程图
FlowDecision
FlowDecision 活动帮助在状态之间转换。
控制流
Sequence
这将包含最后一个状态“订单已完成”。
使用鼠标指针连接活动,使它们看起来类似于如下所示:
单击工作流底部的“变量”打开“变量”面板。
在“变量”面板中,单击“创建变量”,然后创建以下变量:
变量名 变量类型 作用域 注意 poID
字符串
流程图
poID 是 GUID 号。poID 也用作相关性。
isProcessed
布尔型
流程图
它是一个标志,表示订单是否已成功处理。
isShipped
布尔型
流程图
它是一个标志,表示订单是否已发售。
isUpdated
布尔型
流程图
它是一个标志,表示订单是否已由客户更新。
po
PurchaseOrder
流程图
这是一个在 OrderProcessingService 中定义的自定义数据类型。它包含采购订单信息。
poUpdate
PurchaseOrder
流程图
它包含客户要更新 PO 时已更新的 PO 信息。
correlationorderWorkflow
CorrelationHandle
流程图
这是相关句柄,用于连接到服务的客户端,以及连接到 OrderProcessService 和 ShippingService 的服务。
以下是所创建的变量的屏幕截图:
在工作流中,单击“流程图”活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
订单服务
在工作流中,单击第一个“序列”活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
等待订单
在工作流中,单击第二个“序列”活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
订单已打开
在工作流中,单击第三个“序列”活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
订单已处理
在工作流中,单击第四个“序列”活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
订单已完成
在工作流中,单击第一个“FlowDecision”活动,然后在“属性”面板中设置以下值。
属性 值 条件
isProcessed
FalseLabel
已更新
TrueLabel
已处理
在工作流中,单击第二个“FlowDecision”活动,然后在“属性”面板中设置以下值。
属性 值 条件
isShipped
FalseLabel
已更新
TrueLabel
已发售
您已经定义了状态机工作流的主要结构。您现在将定义每个状态。
在工作流中,双击“等待订单”。注意,路径显示在选项卡下。您可以单击“订单服务”以返回到您会看到整个状态机工作流的页面。
将以下活动按显示顺序从工具箱拖动到工作流:
类别 活动 注意 基元
Assign
此分配活动将为订单获取一个订单 ID (GUID)。
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowSerivce
SendNotification
此自定义活动将电子邮件通知发送到客户端。
基元
Assign
使用此分配活动,以便能够监控采购订单产品。
基元
Assign
使用此分配活动,以便能够监控采购订单数量。
重新排列这些活动,使它看起来类似于如下所示:
单击工作流底部的“变量”打开“变量”面板。
在“变量”面板中,单击“创建变量”,然后创建以下变量:
变量名 变量类型 作用域 注意 product
字符串
等待订单
AppFabric 可以跟踪工作流变量。创建此变量,以便能够跟踪产品名称。
quantity
Int32
等待订单
此变量用于进行跟踪。
在工作流中,单击“接收”活动,然后在“属性”面板中设置以下值。
属性 值 内容
消息;消息数据:po;消息类型:Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderProcessingService.Purchaseorder
DisplayName
接收 PO
OperationName
SubmitPO
SerivceContractName
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService
CanCreateInstance
(已选择)
在工作流中,单击第一个“分配”活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
分配 PO ID
到
po.POID
值
System.Guid.NewGuid().ToString()
在工作流中,单击“SendReplyToReceive”活动,然后在“属性”面板中设置以下值。
属性 值 内容
消息;消息数据:po.POID;消息类型:字符串
CorrelationInitializers
CorrelationOrderWorkflow;Query correlation initialize; key1=sm:body()/xg0:string
备注
您刚才的操作称为关联。此工作流具有以下七个接收活动:一个接收采购订单的活动、一个接收流程服务结果的活动、一个接收发售服务结果的活动、两个接收客户端更新的活动,还有两个接收客户端取消的活动。在收到采购订单之后,工作流服务会生成一个 GUID 号,作为订单编号。设想一下工作流服务同时收到多个采购订单的情况。工作流引擎会为每个采购订单请求创建一个工作流实例。工作流引擎需要将其他六个请求与工作流实例相匹配(或相关联)。为此,工作流引擎就要求每个关联都有一个唯一的标识符。在本示例中,唯一的标识符就是订单编号 (GUID)。在第一个 SendReplyToReceive 活动中,您将定义一个 CorrelationInitializer。您选择“查询相关初始值设定项”查询类型,该类型表示唯一的标识符在传递给接收活动的邮件中。您还将指定到该字段的 xPath。除了相关初始值设定项之外,您还必须在 CorrelateWith 字段中指定“相关句柄”。“相关句柄”是容纳相关数据的容器,因此可以在工作流中的任何位置检索相关数据。在后续接收中,您将指定相同的相关句柄。您将在 CorrelateOn 字段中指定如何从接收到的邮件中检索订单编号。
在工作流中,单击“SendNotification”活动,然后在“属性”面板中设置以下值。
属性 值 Body
"We have received your order. Your order number is " + po.POID
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~Order Received"
To
po.EmailAddress
在工作流中,单击第二个“分配”活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
指定产品名称
To
产品
Value
po.Description
在工作流中,单击第三个“分配”活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
指定数量
To
quantity
Value
po.Quantity
您已经实现了等待订单状态。
在选项卡名称下,单击“订单服务”以显示“订单服务”流程图活动。
在工作流中,双击“订单已打开”序列活动以实现此状态。
将以下活动按显示顺序从工具箱拖动到工作流:
类别 活动 注意 基元
分配
控制流
并行
将以下活动拖动到“并行”活动中:
类别 活动 注意 控制流
序列
将以下活动拖动到“序列”活动中:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService.Activities
ProcessOrder
运行时
永久
消息
接收
Microsoft.Samples.Dublin.Tutorials.OrderService.orderWorkflowService
SendNotification
基元
分配
将以下活动拖动到 Parallel 活动中以及现有 Sequence 活动的右侧:
类别 活动 注意 消息
ReceiveAndSendReply
ReceiveAndSendReply 活动是包含 Sequence 活动(其中包括 Receive 活动和 SendReplyToReceive 活动)的复合活动。
将以下活动拖动到新添加的 Sequence 活动中并放在 Receive 和 SendReplyToReceive 这两个活动下:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService.Activities
CancelOrderProcess
控制流
If
将以下活动拖动到 If 活动的 Then 分支中:
类别 活动 注意 控制流
Sequence
将以下活动拖动到新添加的 Sequence 活动中:
类别 活动 注意 基元
分配
基元
分配
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService
SenNotification
将以下活动拖动到 If 活动的 Else 分支中:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService
SenNotification
将以下活动拖动到 Parallel 活动中,使之成为最右边的分支:
类别 活动 注意 消息
ReceiveAndSendReply
将以下活动拖动到新添加的 Sequence 活动中并放在 Receive 和 SendReplyToReceive 这两个活动下:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService.Activities
CancelOrderProcess
控制流
If
将以下活动拖动到 If 活动的 Then 分支中:
类别 活动 注意 Control Flow
Sequence
将以下活动拖动到新添加的 Sequence 活动中:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService
SenNotification
运行时
TerminateWorkflow
将以下活动拖动到 If 活动的 Else 分支中:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService
SenNotification
在添加这些活动后,已打开订单的状态看起来类似于以下内容:
单击 Parallel 活动最左边分支上的 Sequence 活动,然后单击工作流底部的“变量”以打开“变量”面板。
在“变量”面板中,单击“创建变量”,然后创建以下变量:
变量名 变量类型 作用域 注意 cancelOrderProcessAcknowledgement
字符串
并行
ProcessServiceResult
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.ProcessServiceResult
序列
processServiceAcknowledgement
字符串
序列
在工作流中,单击 Parallel 活动顶部的“Assign” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
初始化 isUpdated
To
isUpdated
值
False
在工作流中,单击“Parallel” 活动,然后在“属性”面板中设置以下值。
属性 值 Completion
isUpdated Or isProcessed
DisplayName
处理订单
在工作流中,单击 Parallel 活动最左边分支上的“Sequence” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
处理
在工作流中,单击 Parallel 活动最左边分支上的“ProcessOrder” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
处理订单
po
po
ProcessOrderResult
processServiceAcknowledgement
在工作流中,单击 Parallel 活动最左边分支上的“Receive” 活动,然后在“属性”面板中设置以下值。
属性 值 内容
Message; Message data:processServiceResult; Message type:Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.ProcessServiceResult
DisplayName
接收处理结果
OperationName
SubmitProcessResult
ServiceContractName
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService
CanCreateInstance
(清除)
CorrelationOn
CorrelationWith:correlationOrderWorkflow; XPath Queries:key1=sm:body()/xg0:ProcessServiceResult/sg0:POID
CorrelationWith
correlationOrderWorkflow
在工作流中,单击 Parallel 活动最左边分支上的“SendNotification” 活动,然后在“属性”面板中设置以下值。
属性 值 Body
"Order with order#" + po.POID + " has been processed, and is ready for shipping."
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~Order Processed"
To
po.EmailAddress
在工作流中,单击 Parallel 活动最左边分支上的“Assign” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
设置 isProcessed 标记
To
isProcessed
值
True
您已经配置完 Parallel 活动最左边的分支。
在工作流中,单击 Parallel 活动中间分支上的“Sequence” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
等待更新
在工作流中,单击 Parallel 活动中间分支上的“Receive” 活动,然后在“属性”面板中设置以下值。
属性 值 内容
Message; Message data:poUpdate; Message type:Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderProcessingService.PurchaseOrder
DisplayName
接收更新
OperationName
SubmitUpdate
ServiceContractName
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService
CanCreateInstance
(清除)
CorrelationOn
CorrelationWith:correlationOrderWorkflow; XPath Queries:key1=sm:body()/xg0:PurchaseOrder/xg0:POID
CorrelationWith
correlationOrderWorkflow
在工作流中,单击 Parallel 活动中间分支上的“SendReplyToReceive” 活动,然后在“属性”面板中设置以下值。
属性 值 内容
Message; Message data:“已收到 PO 更新”; 消息类型:字符串
DisplayName
确认接收更新
在工作流中,单击 Parallel 活动中间分支上的“CancelOrderProcess” 活动,然后在“属性”面板中设置以下值。
属性 值 CancelOrderProcessResult
cancelOrderProcessAcknowledgement
DisplayName
取消订单处理
orderID
po.POID
在工作流中,单击 Parallel 活动中间分支上的“If” 活动,然后在“属性”面板中设置以下值。
属性 值 条件
cancelOrderProcessAcknowledgement = "The order process has been terminated successfully."
DisplayName
检查取消状态
在工作流中,单击 If 活动 Then 分支上的“Sequence” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
取消成功序列
在工作流中,单击 If 活动 Then 分支上的第一个“Assign” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
刷新 PO
To
po
值
poUpdate
在工作流中,单击 If 活动 Then 分支上的第二个“Assign” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
设置 isUpdated 标记
To
isUpdated
值
True
在工作流中,单击 If 活动 Then 分支上的“SendNotification” 活动,然后在“属性”面板中设置以下值。
属性 值 Body
"Your order has updated upon your request. The order is under processing."
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~Order Updated (by customer)"
To
po.EmailAddress
在工作流中,单击 If 活动 Else 分支上的“SendNotification” 活动,然后在“属性”面板中设置以下值。
属性 值 Body
"Your order update request cannot be processed. Please try again."
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~Order Update (by customer) Failed"
To
po.EmailAddress
您已经配置完 Parallel 活动中间的分支。
在工作流中,单击 Parallel 活动最右边分支上的“Sequence” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
等待取消
在工作流中,单击 Parallel 活动最右边分支上的“Receive” 活动,然后在“属性”面板中设置以下值。
属性 值 内容
Message; Message data:poID; Message type:String
DisplayName
接收取消
OperationName
SubmitCancellation
ServiceContractName
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService
CanCreateInstance
(清除)
CorrelationOn
CorrelationWith:correlationOrderWorkflow; XPath Queries:key1=sm:body()/xg0:string
CorrelationWith
correlationOrderWorkflow
在工作流中,单击 Parallel 活动最右边分支上的“SendReplyToReceive” 活动,然后在“属性”面板中设置以下值。
属性 值 内容
Message; Message data:“PO cancellation received”; Message type:String
DisplayName
确认收到取消
在工作流中,单击 Parallel 活动最右边分支上的“CancelOrderProcess” 活动,然后在“属性”面板中设置以下值。
属性 值 CancelOrderProcessResult
cancelOrderProcessAcknowledgement
DisplayName
取消订单处理
orderID
po.POID
在工作流中,单击 Parallel 活动最右边分支上的“If” 活动,然后在“属性”面板中设置以下值。
属性 值 条件
cancelOrderProcessAcknowledgement = "The order process has been terminated successfully."
DisplayName
检查取消状态
在工作流中,单击 If 活动 Then 分支上的“Sequence” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
取消成功序列
在工作流中,单击 If 活动 Then 分支上的“SendNotification” 活动,然后在“属性”面板中设置以下值。
属性 值 Body
"Your order has been cancelled upon your request."
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~Order Cancelled (by customer)"
To
po.EmailAddress
在工作流中,单击 If 活动 Then 分支上的“TerminateWorkflow” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
终止工作流
原因
“Client cancellation”
在工作流中,单击 If 活动 Else 分支上的第二个“SendNotification” 活动,然后在“属性”面板中设置以下值。
属性 值 Body
"Your order cancellation request cannot be processed. Please try again."
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~Order Cancellation(by customer) Failed"
To
po.EmailAddress
您已经配置完 Parallel 活动最右边的分支。
在选项卡名称下,单击“订单服务”以显示“订单服务”流程图活动。
在工作流中,双击“订单已处理”序列活动以实现此状态。
将以下活动按显示顺序从工具箱拖动到工作流:
类别 活动 注意 基元
分配
控制流
并行
将以下活动拖动到“并行”活动中:
类别 活动 注意 控制流
序列
将以下活动拖动到“序列”活动中:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.ShippingService.Activities
ShipOrder
运行时
永久
消息
接收
基元
分配
将以下活动拖动到 Parallel 活动中以及现有 Sequence 活动的右侧:
类别 活动 注意 消息
ReceiveAndSendReply
ReceiveAndSendReply 活动是包含 Sequence 活动(其中包括 Receive 活动和 SendReplyToReceive 活动)的复合活动。
将以下活动拖动到新添加的 Sequence 活动中并放在 Receive 和 SendReplyToReceive 这两个活动下:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.ShippingService.Activities
CancelShipping
控制流
If
将以下活动拖动到 If 活动的 Then 分支中:
类别 活动 注意 控制流
序列
将以下活动拖动到新添加的 Sequence 活动中:
类别 活动 注意 基元
分配
基元
分配
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService
SendNotification
将以下活动拖动到 If 活动的 Else 分支中:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService
SendNotification
将以下活动拖动到 Parallel 活动中,使之成为最右边的分支:
类别 活动 注意 消息
ReceiveAndSendReply
将以下活动拖动到新添加的 Sequence 活动中并放在 Receive 和 SendReplyToReceive 这两个活动下:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.ShippingService.Activities
CancelShipping
控制流
If
将以下活动拖动到 If 活动的 Then 分支中:
类别 活动 注意 控制流
序列
将以下活动拖动到新添加的 Sequence 活动中:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService
SendNotification
运行时
TerminateWorkflow
将以下活动拖动到 If 活动的 Else 分支中:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService
SenNotification
添加这些活动之后,“订单已处理”的状态看起来类似于以下内容:
单击 Parallel 活动最左边分支上的 Sequence 活动,然后单击工作流底部的“变量”以打开“变量”面板。
在“变量”面板中,单击“创建变量”,然后创建以下变量:
变量名 变量类型 作用域 注意 cancelShippingAcknowledgement
字符串
并行
ShippingServiceResult
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.ShippingServiceResult
序列
shippingServiceAcknowledgement
字符串
序列
在工作流中,单击 Parallel 活动顶部的“Assign” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
初始化 isUpdated
To
isUpdated
值
False
在工作流中,单击“Parallel” 活动,然后在“属性”面板中设置以下值。
属性 值 完成
isUpdated Or isShipped
DisplayName
发售订单
在工作流中,单击 Parallel 活动最左边分支上的“Sequence” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
发售
在工作流中,单击 Parallel 活动最左边分支上的“ShipOrder” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
发售订单
poID
po.POID
ShipOrderResult
shippingServiceAcknowledgement
在工作流中,单击 Parallel 活动最左边分支上的“Receive” 活动,然后在“属性”面板中设置以下值。
属性 值 内容
Message; Message data:shippingServiceResult; Message type:Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.ShippingServiceResult
DisplayName
接收发售结果
OperationName
SubmitShippingResult
ServiceContractName
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService
CanCreateInstance
(清除)
CorrelationOn
CorrelationWith:correlationOrderWorkflow; XPath Queries:key1=sm:body()/xg0:ShippingServiceResult/xg0:POID
CorrelationWith
correlationOrderWorkflow
在工作流中,单击 Parallel 活动最左边分支上的“Assign” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
设置 isShipped 标志
To
isShipped
值
True
您已经配置完 Parallel 活动最左边的分支。
在工作流中,单击 Parallel 活动中间分支上的“Sequence” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
等待更新
在工作流中,单击 Parallel 活动中间分支上的“Receive” 活动,然后在“属性”面板中设置以下值。
属性 值 内容
Message; Message data:poUpdate; Message type:Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderProcessingService.PurchaseOrder
DisplayName
接收更新
OperationName
SubmitUpdate
ServiceContractName
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService
CanCreateInstance
(清除)
CorrelationOn
CorrelationWith:correlationOrderWorkflow; XPath Queries:key1=sm:body()/xg0:PurchaseOrder/xg0:POID
CorrelationWith
correlationOrderWorkflow
在工作流中,单击 Parallel 活动中间分支上的“SendReplyToReceive” 活动,然后在“属性”面板中设置以下值。
属性 值 内容
Message; Message data:“PO update received”; Message type:String
DisplayName
确认接收更新
在工作流中,单击 Parallel 活动中间分支上的“CancelShipping” 活动,然后在“属性”面板中设置以下值。
属性 值 CancelShippingResult
cancelShippingAcknowledgement
DisplayName
取消发售
orderID
poUpdate.POID
在工作流中,单击 Parallel 活动中间分支上的“If” 活动,然后在“属性”面板中设置以下值。
属性 值 条件
cancelShippingAcknowledgement = "The shipping process has been terminated successfully."
DisplayName
检查取消状态
在工作流中,单击 If 活动 Then 分支上的“Sequence” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
取消成功序列
在工作流中,单击 If 活动 Then 分支上的第一个“Assign” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
刷新 PO
To
po
值
poUpdate
在工作流中,单击 If 活动 Then 分支上的第二个“Assign” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
设置 isUpdated 标记
To
isUpdated
值
True
在工作流中,单击 If 活动 Then 分支上的“SendNotification” 活动,然后在“属性”面板中设置以下值。
属性 值 Body
"Your order has updated upon your request. The order is under processing."
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~Order Updated (by customer)"
To
po.EmailAddress
在工作流中,单击 If 活动 Else 分支上的“SendNotification” 活动,然后在“属性”面板中设置以下值。
属性 值 Body
"Your order update request cannot be processed. The order has been shipped."
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~Order Update (by customer) Failed"
To
po.EmailAddress
您已经配置完 Parallel 活动中间的分支。
在工作流中,单击 Parallel 活动最右边分支上的“Sequence” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
等待取消
在工作流中,单击 Parallel 活动最右边分支上的“Receive” 活动,然后在“属性”面板中设置以下值。
属性 值 内容
Message; Message data:poID; Message type:String
DisplayName
接收取消
OperationName
SubmitCancellation
ServiceContractName
Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService
CanCreateInstance
(清除)
CorrelationOn
CorrelationWith:correlationOrderWorkflow; XPath Queries:key1=sm:body()/xg0:string
CorrelationWith
correlationOrderWorkflow
在工作流中,单击 Parallel 活动最右边分支上的“SendReplyToReceive” 活动,然后在“属性”面板中设置以下值。
属性 值 内容
Message; Message data:“PO cancellation received”; Message type:String
DisplayName
确认收到取消
在工作流中,单击 Parallel 活动最右边分支上的“CancelShipping” 活动,然后在“属性”面板中设置以下值。
属性 值 CancelshippingResult
cancelShippingAcknowledgement
DisplayName
取消发售
poID
po.POID
在工作流中,单击 Parallel 活动最右边分支上的“If” 活动,然后在“属性”面板中设置以下值。
属性 值 条件
cancelShippingAcknowledgement = "The shipping process has been terminated successfully."
DisplayName
检查取消状态
在工作流中,单击 If 活动 Then 分支上的“Sequence” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
取消成功序列
在工作流中,单击 If 活动 Then 分支上的“SendNotification” 活动,然后在“属性”面板中设置以下值。
属性 值 Body
"We are sorry you chose to cancel your order. If there is anything we can do to help you with our order process or with our products or services please do not hesitate to contact us."
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~Order Cancelled (by cusotmer)"
To
po.EmailAddress
在工作流中,单击 If 活动 Then 分支上的“TerminateWorkflow” 活动,然后在“属性”面板中设置以下值。
属性 值 DisplayName
终止工作流
原因
“Client cancellation”
在工作流中,单击 If 活动 Else 分支上的第二个“SendNotification” 活动,然后在“属性”面板中设置以下值。
属性 值 Body
"Your order cancellation request cannot be processed. The order has been shipped.
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~Order Cancellation(by customer) Failed"
To
po.EmailAddress
您已经配置完 Parallel 活动最右边的分支。
在选项卡名称下,单击“订单服务”以显示“订单服务”流程图活动。
在工作流中,双击“订单已完成”序列活动以实现此状态。
将以下活动按显示顺序从工具箱拖动到工作流:
类别 活动 注意 Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService
SendNotification
在工作流中,单击 If 活动 Else 分支上的第二个“SendNotification” 活动,然后在“属性”面板中设置以下值。
属性 值 Body
"Your order has been shipped. Thank you for shopping at contoso.com."
DisplayName
发送客户端通知
Subject
"Contoso.com Order#" + po.POID + "~~ Order Shipped"
To
po.EmailAddress
您已经完成工作流开发。
在此配置文件中,您将定义两个终结点和一个行为元素。
使用配置文件配置订单工作流服务的步骤
在“解决方案资源管理器”中,展开“OrderWorkflowService”,然后双击“Web.config”将其打开。
在 <system.serviceModel> 标记中添加 <services> 标记。
<services> <service name="Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderWorkflow"> <endpoint address="" binding="basicHttpBinding" contract="Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services>
编译订单工作流服务的步骤
- 在“解决方案资源管理器”中,右键单击“OrderWorkflowService” 项目,然后单击“重建”。确保此项目在“输出”窗口中成功编译。
完成订单处理服务
OrderProcessingService 和 OrderWorkflowService 相互引用。因此,您在完成 OrderWorkflowService 后必须完成 OrderProcessingService。
添加服务引用的步骤
在“解决方案资源管理器”中,右键单击“OrderProcessingService”,然后单击“添加服务引用”。
在“添加服务引用”中,单击“发现”。Visual Studio 应会发现这两个服务。
输入并选择以下值,然后单击“确定”以创建服务引用。
属性 值 服务
OrderWorkflow.xamlx
Namespace
OrderWorkflowService
修改 OrderProcess.svc 的步骤
在“解决方案资源管理器”中,展开“OrderProcessingService”,然后双击“OrderProcessing.svc”将其打开。
取消对 SendProcessResult 函数中该节的注释,因此该函数看起来类似于如下所示:
private void SendProcessResult(object state) { PurchaseOrder po = (PurchaseOrder)state; WorkItem workItem = new WorkItem(Thread.CurrentThread); WorkItemMap.Add(po.POID, workItem); //Simulating the order processing process Thread.Sleep(120000); //The following portion will be uncommented after referencing OrderWorkflowService OrderWorkflowService.ProcessServiceResult reply = new OrderWorkflowService.ProcessServiceResult(); reply.POID = po.POID; reply.Message = "The order has been processed successfully."; lock (workItem.WorkItemLock) { using (OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient client = new OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient()) { client.SubmitProcessResult(reply); } workItem.Complete(); WorkItemMap.Remove(po.POID); } }
编译订单处理服务的步骤
- 在“解决方案资源管理器”中,右键单击“OrderProcessingService”项目,然后单击“重建”。确保此项目在“输出”窗口中成功编译。
完成发售服务
ShippingService 和 OrderWorkflowService 相互引用。因此,您在完成 OrderWorkflowService 后必须完成 ShipingService。
添加服务引用的步骤
在“解决方案资源管理器”中,右键单击“ShippingService”,然后单击“添加服务引用”。
在“添加服务引用”中,单击“发现”。Visual Studio 应会发现这两个服务。
输入并选择以下值,然后单击“确定”以创建服务引用。
属性 值 服务
OrderWorkflow.xamlx
Namespace
OrderWorkflowService
修改 Shipping.svc 的步骤
在“解决方案资源管理器”中,展开“ShippingService”,然后双击“Shipping.svc”将其打开。
撤消对 SendShippingResult 函数中该节的注释,因此该函数看起来类似于如下所示:
private void SendShippingResult(object state) { string poID = state.ToString(); WorkItem workItem = new WorkItem(Thread.CurrentThread); WorkItemMap.Add(poID, workItem); //Simulating the order processing process Thread.Sleep(60000); //The following portion will be uncommented after referencing OrderWorkflowService OrderWorkflowService.ShippingServiceResult reply = new OrderWorkflowService.ShippingServiceResult(); reply.POID = poID; reply.Message = "The order has been shipped."; lock (workItem.WorkItemLock) { using (OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient client = new OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient()) { client.SubmitShippingResult(reply); } workItem.Complete(); WorkItemMap.Remove(poID); } }
编译发售服务的步骤
- 在“解决方案资源管理器”中,右键单击“ShippingService”项目,然后单击“重建”。确保此项目在“输出”窗口中成功编译。
开发订单客户端应用程序
在此步骤中,您将开发 Windows 窗体客户端应用程序。
向解决方案中添加 Windows 窗体应用程序项目的步骤
在“解决方案资源管理器”中,右键单击“解决方案‘OrderService’”,指向“添加”,然后单击“新项目”。
在“添加新项目”中,选择或键入以下值,然后单击“确定”。
属性 值 项目类型
Visual C#/Windows
模板
Windows 窗体应用程序
名称
OrderClient
位置
C:\DublinTutorial\OrderServiceSolution\OrderService
订单客户端是工作流服务的接口。您必须向工作流服务中添加服务引用。
添加服务引用的步骤
在“解决方案资源管理器”中,右键单击“OrderClient”,然后单击“添加服务引用”打开“添加服务引用”对话框。
在“添加服务引用”中,单击“发现”。
输入并选择以下值,然后单击“确定”以创建服务引用。
属性 值 服务
OrderWorkflow.xamlx
Namespace
OrderWorkflowService
开发 Windows 窗体的步骤
在“解决方案资源管理器”中,展开“OrderClient”,然后双击“Form1.cs”将其打开。
右键单击“Form1.cs”,再单击“重命名”,然后键入“OrderForm.cs”。
出现提示时单击“是”。
从工具箱中添加四个“标记”控件、五个“TextBox”控件和三个“按钮”控件,并将这些控件对齐,使之看起来类似于以下屏幕截图:
在工作流中,单击此窗体,然后在“属性”面板中设置以下值。
属性 值 Name
OrderForm
Text
Contoso.com 订单窗体
在工作流中,单击“label1”,然后在“属性”面板中设置以下值。
属性 值 Name
lblOrderNumber
Text
订单编号:
在工作流中,单击“label2”,然后在“属性”面板中设置以下值。
属性 值 Name
lblEmail
Text
电子邮件:
在工作流中,单击“label3”,然后在“属性”面板中设置以下值。
属性 值 Name
lblDescription
Text
描述:
在工作流中,单击“label4”,然后在“属性”面板中设置以下值。
属性 值 Name
lblQuantity
Text
数量:
在工作流中,单击“textbox1”,然后在“属性”面板中设置以下值。
属性 值 Name
txtOrderNumber
已启用
False
在工作流中,单击“textbox2”,然后在“属性”面板中设置以下值。
属性 值 Name
txtEmail
Text
JohnDole@fabrikam.com
在工作流中,单击“textbox3”,然后在“属性”面板中设置以下值。
属性 值 Name
txtDescription
Text
Windows 7
在工作流中,单击“textbox4”,然后在“属性”面板中设置以下值。
属性 值 Name
txtQuantity
Text
10
在工作流中,单击“textbox5”,然后在“属性”面板中设置以下值。
属性 值 Name
txtStatus
Anchor
底部,左侧,右侧
已启用
False
Text
“”
在工作流中,单击“button1”,然后在“属性”面板中设置以下值。
属性 值 Name
btnSubmit
Anchor
底部,右侧
Text
Submit
单击(在“事件”选项卡下)
btnSubmit_Click
在工作流中,单击“button2”,然后在“属性”面板中设置以下值。
属性 值 Name
btnUpdate
Anchor
底部,右侧
Text
更新
单击(在“事件”选项卡下)
btnUpdate_Click
在工作流中,单击“button3”,然后在“属性”面板中设置以下值。
属性 值 Name
btnCancel
Anchor
底部,右侧
Text
取消
单击(在“事件”选项卡下)
btnCancel_Click
在“解决方案资源管理器”中,右键单击“OrderForm.cs”,然后单击“查看代码”。
右键单击“OrderClient”命名空间,单击“重构”,然后单击“重命名”以打开“重命名”对话框。
在“重命名”中,键入“Microsoft.Samples.Dublin.Tutorials.OrderService.OrderClient”,然后单击“确定”。
单击“应用”。
使用以下内容替换此代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Microsoft.Samples.Dublin.Tutorials.OrderService.OrderClient { public partial class OrderForm : Form { //Delegates to make all service calls on a secondary thread private delegate void SubmitOrderDelegate(); private delegate void CancelOrderDelegate(); private delegate void UpdateOrderDelegate(); private delegate void CallbackDelegate(string poID, string str); private SubmitOrderDelegate SubmitOrderHandler; private CancelOrderDelegate CancelOrderHandler; private UpdateOrderDelegate UpdateOrderHandler; private CallbackDelegate CallbackHandler; public OrderForm() { InitializeComponent(); } private void OrderForm_Load(object sender, EventArgs e) { btnUpdate.Enabled = false; btnCancel.Enabled = false; btnSubmit.Focus(); } #region Submit button private void btnSubmit_Click(object sender, EventArgs e) { btnSubmit.Enabled = false; btnCancel.Enabled = false; btnUpdate.Enabled = false; txtEmail.Enabled = false; txtStatus.Text = "Connecting to the Order service ..."; //Executed on secondary thread so the UI thread is not blocked SubmitOrderHandler = new SubmitOrderDelegate(this.SubmitOrder); SubmitOrderHandler.BeginInvoke(null, null); } private void SubmitOrder() { string strMessage = "Your order has been received."; string strPOID = ""; OrderWorkflowService.PurchaseOrder po = new OrderWorkflowService.PurchaseOrder(); po.EmailAddress = txtEmail.Text; po.Description = txtDescription.Text; po.Quantity = System.Int32.Parse(txtQuantity.Text); //A Blocking service call executed on secondary thread try { OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient client = new OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient(); strPOID = client.SubmitPO(po); client.Close(); } catch (Exception Ex) { strMessage = "Error: " + Ex.Message; } //Make UI updates back on the primary thread CallbackHandler = new CallbackDelegate(this.SubmitOrderCallBack); this.BeginInvoke(CallbackHandler, strPOID, strMessage); } private void SubmitOrderCallBack(string strPOID, string strMessage) { //UI updates back on the primary thread btnUpdate.Enabled = true; btnCancel.Enabled = true; txtOrderNumber.Text = strPOID; txtStatus.Text = strMessage; } #endregion #region Update button private void btnUpdate_Click(object sender, EventArgs e) { btnUpdate.Enabled = false; btnCancel.Enabled = false; txtStatus.Text = "Connecting to the Order service ..."; //Executed on secondary thread so the UI thread is not blocked UpdateOrderHandler = new UpdateOrderDelegate(this.UpdateOrder); UpdateOrderHandler.BeginInvoke(null, null); } private void UpdateOrder() { string strMessage = "Your order update request has been received."; string strPOID = ""; OrderWorkflowService.PurchaseOrder po = new OrderWorkflowService.PurchaseOrder(); po.POID = txtOrderNumber.Text; po.EmailAddress = txtEmail.Text; po.Description = txtDescription.Text; po.Quantity = System.Int32.Parse(txtQuantity.Text); try { OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient client = new OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient(); strMessage = client.SubmitUpdate(po); client.Close(); } catch (Exception Ex) { strMessage = "Error: " + Ex.Message; } //Make UI updates back on the primary thread CallbackHandler = new CallbackDelegate(this.UpdateOrderCallback); this.BeginInvoke(CallbackHandler, strPOID, strMessage); } private void UpdateOrderCallback(string strPOID, string strMessage) { //UI updates back on the primary thread btnUpdate.Enabled = true; btnCancel.Enabled = true; txtStatus.Text = strMessage; } #endregion #region Cancel button private void btnCancel_Click(object sender, EventArgs e) { btnUpdate.Enabled = false; btnCancel.Enabled = false; txtStatus.Text = "Connecting to the Order service ..."; //Executed on secondary thread so the UI thread is not blocked CancelOrderHandler = new CancelOrderDelegate(this.CancelOrder); CancelOrderHandler.BeginInvoke(null, null); } private void CancelOrder() { string strInOut = txtOrderNumber.Text; try { OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient client = new OrderWorkflowService.MicrosoftSamplesDublinTutorialsOrderServiceOrderWorkflowServiceIOrderWorkflowServiceClient(); client.SubmitCancellation(ref strInOut); client.Close(); } catch (Exception Ex) { strInOut = "Error: " + Ex.Message; } //Make UI updates back on the primary thread CallbackHandler = new CallbackDelegate(this.CancelOrderCallback); this.BeginInvoke(CallbackHandler, txtOrderNumber.Text, strInOut); } private void CancelOrderCallback(string strPOID, string strMessage) { //UI updates back on the primary thread //btnUpdate.Enabled = true; //btnCancel.Enabled = true; txtStatus.Text = strMessage; } #endregion } }
编译订单客户端的步骤
- 在“解决方案资源管理器”中,右键单击“OrderClient” 项目,然后单击“重建”。确保此项目在“输出”窗口中成功编译。
测试订单服务
测试订单服务的步骤
在“解决方案资源管理器”中,右键单击“OrderClient”,然后单击“设置为启动项目”。
在 Visual Studio 中,单击“调试”菜单,然后单击“开始调试”。您应会看到打开一个 Windows 窗体。
在该窗体中,单击“提交”。
打开 Windows 资源管理器并浏览到 C:\DublinTutorial\Inbox 文件夹。
请稍等,直到您看到全部三个电子邮件通知。看到全部这三个文件大概要用三到四分钟的时间。
将订单服务打包
将 OrderProcessingService WCF 服务打包的步骤
在“解决方案资源管理器”中,右键单击“OrderProcessingService” 项目,然后单击“打包/发布设置”。
输入以下值:
属性 值 以 ZIP 文件的形式创建一个 Web 包
(已选择)
创建该数据包的位置
C:\DublinTutorial\DeploymentPackages\OrderProcessingService.zip
要在目标服务器上使用的 IIS 网站/应用程序名称
OrderService/OrderProcessingService
在“解决方案资源管理器”中,右键单击“OrderProcessingService”项目,然后单击“创建包”。
使用以下设置重复上述过程,为其他三个项目创建程序包:
项目名称 创建该数据包的位置 要在目标服务器上使用的 IIS 网站/应用程序名称 OrderWorkflowService
C:\DublinTutorial\DeploymentPackages\OrderWorkflowService.zip
OrderService/OrderWorkflowService
ShippingService
C:\DublinTutorial\DeploymentPackages\ShippingService.zip
OrderService/ShippingService
备注
您可以考虑更新 Web.config 文件中相关服务的终结点地址,以反映打包服务之前部署程序包的服务器。
另请参阅
概念
Windows Server AppFabric 界面的使用教程
使用 Windows PowerShell 的教程
2011-12-05