Share via


Appendix A: Developing the Order Application

This appendix provides the detailed steps for developers to build the Contoso Order service. The purpose of this appendix is to familiarize developers with developing applications that include Windows Communication Foundation (WCF) and/or Windows Workflow Foundation (WF) services using by Visual Studio 1010 and the .NET Framework 4. The main portion of the tutorial uses this application to show system administrators or application owners how to use Microsoft AppFabric 1.1 for Windows Server to deploy, monitor, and troubleshoot applications that include WCF and/or WF services.

This Contoso Order service consists of the following four applications:

  • Order Process service: A WCF service that simulates calling an existing order processing application through the Web service interfaces.

  • Shipping service: A WCF service that simulates calling an existing shipping application through APIs.

  • Order Workflow service: A WF workflow service that manages the order process, including receiving the order, processing the order, and shipping the order.

  • Order client: A Windows Form application that serves as the front end to the Order service.

Note

The Appendix does not require you to install Windows Server AppFabric. But you must first install the Tutorial Using the Microsoft AppFabric 1.1 for Windows Server Interface files to create the proper file structure for the Appendix to build correctly. Note that you are not required to go through and complete the Tutorial Using the Microsoft AppFabric 1.1 for Windows Server Interface tutorial first for the Appendix - just install the files. For the installation procedure of the Tutorial Using the Microsoft AppFabric 1.1 for Windows Server Interface tutorial, see Lesson 1: Getting Started. The C:\DublinTutorial\OrderServiceSolution\Completed folder contains a copy of the completed solution.

Procedure

You will go through the following steps to create the application:

  1. Developing the Order Processing WCF service

  2. Developing the Shipping WCF service

  3. Developing the Order Workflow WF service

  4. Finishing the Order Processing WCF service

  5. Finishing the Shipping WCF service

  6. Developing the Order client application

  7. Packaging the Order service

Developing the Order Processing WCF Service

The Order Processing application is an application that Contoso purchased. It comes with Web services that other applications can communicate with. As a Contoso developer, you need to develop a WCF service called OrderProcessingService to interact with the Order Processing application.

To create a Visual Studio solution and a WCF Service Application for OrderProcessingService

  1. Click Start, point to All Programs, point to Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

  2. From the File menu, click New, and then click New Project.

  3. From New Project, choose or type the following values, and then click OK.

    Property Value

    Project types

    Visual C#/Web

    Templates

    WCF Service Application

    Name

    OrderProcessingService

    Location

    C:\DublinTutorial\OrderServiceSolution

    Solution Name

    OrderService

    Create directory for solution

    (selected)

  4. From Solution Explorer, expand OrderProcessingService, right-click IService1.cs, and then click Delete.

  5. Click OK to confirm deleting the file permanently.

  6. From Solution Explorer, expand OrderProcessingService, right-click Service1.svc, and then click Delete.

  7. Click OK to confirm deleting the file permanently.

The first task for creating a WCF service is to define a contract. The contract specifies what operations the service supports. An operation can be thought of as a Web service method. Each method in the interface corresponds to a specific service operation. In OrderProcessingService, you define two methods, ProcessOrder and CancelOrderProcess.

To define the service contract and data contract for the Order Processing service

  1. From Solution Explorer, right-click OrderProcessService, point to Add, and then click New Item.

  2. From Add New Item - OrderProcessService, select or type the following values, and then click Add.

    Property Value

    Categories

    Visual C#/Web

    Template

    WCF Service

    Name

    OrderProcessing.svc

    Two files are added to the solution: IOrderProcessing.cs and OrderProcessing.svc.

  3. From Solution Explorer, double-click IOrderProcessing.cs to open it.

  4. Right-click the OrderProcessingService namespace, click Refactor, and then click Rename to open the Rename dialog box.

  5. In New name, type Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService, and then click OK.

  6. Click Apply, and then click Yes.

  7. Modify the OrderProcessing.svc source code, so it looks like:

    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;
        }
    }
    

    In this file, you define the data contracts and the service contracts. Clients can call the service to process an order and to cancel the order processing.

After you create the contracts, which are defined by using an interface, the next step is to implement the interface. This involves creating a class called OrderProcessService that implements the user-defined IOrderProcessing interface.

To implement the Order Process service contract

  1. From Solution Explorer, double-click IOrderProcessing.cs to open it.

  2. Modify the source code, so it looks like:

    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;
            }
        }
    }
    

Using a configuration file gives you the flexibility of providing endpoint and service behavior data at the point of deployment instead of at design time. In this configuration file, you define two endpoints.

To configure the Order Process service by using a configuration file

  1. From Solution Explorer, expand OrderProcessingService, and then double-click Web.config to open it. Add a <services> tag inside the <system.serviceModel> tag:

        <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>
    

To compile the Order Process WCF service

  1. From Solution Explorer, right-click the OrderProcessingService project, and then click Rebuild. Make sure the project is compiled successfully in the Output window.

To test the Order Process WCF service

  1. From Solution Explorer, right-click the OrderProcessingService project, and then click View in Browser. An Internet Explorer window opens listing the directory files.

  2. From the Internet Explorer window, click OrderProcessing.svc. Make sure you don’t get any errors.

Developing the Shipping WCF Service

The Shipping service is a WCF service calling a SQL Server store. In the simulation, you don’t really make a database call.

To add a new WCF Service Application project to the solution

  1. From Solution Explorer, right-click Solution ‘OrderService’, point to Add, and then click New Project.

  2. From Add New Project, choose or type the following values, and then click OK.

    Property Value

    Project types

    Visual C#/Web

    Templates

    WCF Service Application

    Name

    ShippingService

    Location

    C:\DublinTutorial\OrderServiceSolution\OrderService

  3. From Solution Explorer, expand ShippingService, right-click IService1.cs, and then click Delete.

  4. Click OK to confirm deleting the file permanently.

  5. From Solution Explorer, expand ShippingService, right-click Service1.svc, and then click Delete.

  6. Click OK to confirm deleting the file permanently.

You define one service contract called IShipping, which contains two operation contracts, ShipOrder and CancelShipping.

To define the Shipping WCF service contract

  1. From Solution Explorer, right-click ShippingService, point to Add, and then click New Item.

  2. From Add New Item - ShippingService, select or type the following values, and then click Add.

    Property Value

    Categories

    Visual C#/Web

    Template

    WCF Service

    Name

    Shipping.svc

    Two files are added to the project, IShipping.cs and Shipping.svc.

  3. From Solution Explorer, double-click IShipping.cs to open it.

  4. Right-click the ShippingService namespace, click Refactor, and then click Rename to open the Rename dialog box.

  5. In New name, type Microsoft.Samples.Dublin.Tutorials.OrderService.ShippingService, and then click OK.

  6. Click Apply, and then click Yes.

  7. Modify the source code, so it looks like:

    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);
        }
    }
    

To implement the Shipping WCF service contract

  1. From Solution Explorer, double-click Shipping.svc to open it.

  2. Modify the source code, so it looks like:

    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;
            }
        }
    }
    

In this configuration file, you define two endpoints.

To configure the Shipping WCF service by using a configuration file

  1. From Solution Explorer, expand ShippingService, and then double-click Web.config to open it. Add a <services> tag inside the <system.serviceModel> tag:

        <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>
    

To compile the Shipping WCF service

  1. From Solution Explorer, right-click the ShippingService project, and then click Rebuild. Make sure the project is compiled successfully in the Output window.

Developing the Order Workflow WF Service

The Order workflow service application is the major portion of the whole service. It orchestrates the whole business process. It receives a purchase order, then it calls OrderProcessingService and ShippingService, and finally it sends an e-mail message to the customer about the purchase order status.

To add a new WCF Workflow Service Application project to the solution

  1. From Solution Explorer, right-click Solution ‘OrderService’, point to Add, and then click New Project.

  2. From Add New Project, choose or type the following values, and then click OK.

    Property Value

    Project types

    Visual C#/Workflow

    Templates

    WCF Workflow Service Application

    Name

    OrderWorkflowService

    Location

    C:\DublinTutorial\OrderServiceSolution\OrderService

OrderWorkflowService consumes OrderProcessingService and ShippingService. You must reference the two services.

To add the service references

  1. From Solution Explorer, right-click OrderWorkflowService, and then click Add Service Reference.

  2. From Add Service Reference, click Discover. Visual Studio should discover both of the services.

  3. Enter and select the following values, and then click OK to create the service reference.

    Property Value

    Services

    OrderProcessing.svc

    Namespace

    OrderProcessService

  4. Repeat the steps to add another service reference with the following values:

    Property Value

    Services

    Shipping

    Namespace

    ShippingService

You need to define a custom workflow activity to use to simulate sending e-mail notifications.

To create a workflow code activity

  1. From Solution Explorer, right-click OrderWorkflowService, point to Add, and then click New Item.

  2. From Add New Item - OrderWorkflowService, select or type the following values, and then click Add.

    Property Value

    Categories

    Visual C#/Workflow

    Template

    Code Activity

    Name

    SendNotification.cs

  3. From Solution Explorer, double-click SendNotification.cs to open it.

  4. Right-click the OrderWorkflowService namespace, click Refactor, and then click Rename to open the Rename dialog box.

  5. In New name, type Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService, and then click OK.

  6. Click Apply, and then click Yes.

  7. Modify the source code, so it looks like:

    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);
                }
    
            }
        }
    }
    

    Notice that the path is hardcoded to “C:\DublinTutorial\Inbox\”.

In the following procedure, you define the data types. These data types are used for OrderProcessingService and ShippingService to send results back to OrderWorkflowService.

To define data types

  1. From Solution Explorer, right-click OrderWorkflowService, point to Add, and then click New Item.

  2. From Add New Item - OrderWorkflowService, select or type the following values, and then click Add.

    Property Value

    Categories

    Visual C#/Code

    Template

    Code File

    Name

    DataTypes.cs

  3. From Solution Explorer, double-click DataTypes.cs to open it.

  4. Modify the source code, so it looks like:

    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;
        }
    }
    
  5. From Solution Explorer, right-click OrderWorkflowService, and then click Rebuild. You must build the project so the code activity is accessible from the workflow that you will develop in the following step. Compilation can also expose the referenced WCF service endpoints to the workflow.

The next step is to define the workflow. The workflow contains several states. You start with defining the states, and then define the details of the states. Each part of the development can contain the following steps:

  1. Compose the workflow by using activities.

  2. Define variables.

  3. Configure the activities.

To define the workflow

  1. From Solution Explorer, expand OrderWorkflowService, right-click Service1.xamlx, and then click Rename. Rename the file to OrderWorkflow.xamlx.

  2. From Solution Explorer, double-click OrderWorkflow.xamlx to open it. There are two activities listed in the Sequential Service: one is called ReceiveRequest, and the other is SendResponse.

  3. Right-click the Sequential Service activity, and then click Delete.

  4. From the workflow, click Drop activity here, and set the following values in the Properties panel.

    Property Value

    configurationName

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderWorkflow

    Name

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderWorkflow

  5. Click Toolbox on the left of the window to open the Toolbox panel, and then pin it to the left side of the window.

  6. Drag the following activities from Toolbox to the workflow where it says “Drop activity here”.

    Category Activity Note

    Flowchart

    Flowchart

    The Flowchart activity is a composite activity containing a Start by default. You will add more activities to it in the following steps.

  7. Drag the following activities from Toolbox to the workflow in the order shown:

    Category Activity Note

    Messaging

    ReceiveAndSendReply

    This is “Wait for order” state.

    Control Flow

    Sequence

    This will contain the second state “Order opened”.

    Flowchart

    FlowDecision

    The FlowDecision activity helps transitioning between states.

    Control Flow

    Sequence

    This will contain the third state “Order processed”.

    Flowchart

    FlowDecision

    The FlowDecision activity helps transitioning between states.

    Control Flow

    Sequence

    This will contain the last state “Order completed”.

  8. Use the mouse pointer to connect the activities so they look like:

    67e7c9dd-77e7-43be-ad5a-797b3b46f6e8

  9. Click Variables on the bottom of the workflow to open the Variables panel.

  10. In the Variables panel, click Create Variable, and then create the following variables:

    Variable name Variable type Scope Note

    poID

    String

    Flowchart

    poID is a GUID number. poID is also used for correlation.

    isProcessed

    Boolean

    Flowchart

    It is a flag indicating whether an order has been processed successfully.

    isShipped

    Boolean

    Flowchart

    It is a flag indicating whether an order has been shipped.

    isUpdated

    Boolean

    Flowchart

    It is a flag indicating whether an order has been updated by customer.

    po

    PurchaseOrder

    Flowchart

    This is a custom data type defined in OrderProcessingService. It contains PO information.

    poUpdate

    PurchaseOrder

    Flowchart

    This contains the updated PO information when customer wants to update the PO.

    correlationorderWorkflow

    CorrelationHandle

    Flowchart

    This is the correlation handle that is used for both client connecting to the service, and the service connecting to OrderProcessService and ShippingService.

    Here is a screenshot of the variables created:

    9208977f-710c-460f-afd8-5c6bd8a792d9

  11. From the workflow, click the Flowchart activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Order service

  12. From the workflow, click the first Sequence activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Wait for order

  13. From the workflow, click the second Sequence activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Order opened

  14. From the workflow, click the third Sequence activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Order processed

  15. From the workflow, click the fourth Sequence activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Order completed

  16. From the workflow, click the first FlowDecision activity, and set the following values in the Properties panel.

    Property Value

    Condition

    isProcessed

    FalseLabel

    Updated

    TrueLabel

    Processed

  17. From the workflow, click the second FlowDecision activity, and set the following values in the Properties panel.

    Property Value

    Condition

    isShipped

    FalseLabel

    Updated

    TrueLabel

    Shipped

    You have defined the main structure of the state machine workflow. You will now define each of the states.

  18. From the workflow, double-click Wait for order. Notice the path is shown under the tab. You can click Order service to go back to the page where you see the whole state machine workflow.

  19. Drag the following activities from Toolbox to the workflow in the order shown:

    Category Activity Note

    Primitives

    Assign

    This Assign activity gets the order an order ID (GUID).

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowSerivce

    SendNotification

    This custom activity sends e-mail notification to client.

    Primitives

    Assign

    This Assign activity is used so that purchase order product can be monitored.

    Primitives

    Assign

    This Assign activity is used so that purchase order quantity can be monitored.

  20. Rearrange the activities so they look like:

    Wait for order state activities

  21. Click Variables on the bottom of the workflow to open the Variables panel.

  22. In the Variables panel, click Create Variable, and then create the following variables:

    Variable name Variable type Scope Note

    product

    String

    Wait for order

    AppFabric is capable of tracking workflow variables. This variable is created so the product name can be tracked.

    quantity

    Int32

    Wait for order

    This variable is for tracking purpose.

  23. From the workflow, click the Receive activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data: po; Message type: Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderProcessingService.Purchaseorder

    DisplayName

    Receive PO

    OperationName

    SubmitPO

    SerivceContractName

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService

    CanCreateInstance

    (selected)

  24. From the workflow, click the first Assign activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Assign PO ID

    To

    po.POID

    Value

    System.Guid.NewGuid().ToString()

  25. From the workflow, click the SendReplyToReceive activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data: po.POID; Message type: string

    CorrelationInitializers

    CorrelationOrderWorkflow;Query correlation initialize; key1=sm:body()/xg0:string

    237be300-a94d-4b8e-a707-83f4d2041f6e

    Note

    What you just did is called correlation. This workflow has seven receive activities: one receiving the purchase order, one receiving the process service result, one receiving the shipping service result, two receiving client updates, and two receiving client cancellations. After receiving the purchase order, the workflow service generates a GUID number as the order number. Imagine that the workflow service receives many purchase orders at the same time. The workflow engine creates a workflow instance for each of the purchase order requests. The workflow engine needs to match (or correlate) the other six requests to the workflow instances. To accomplish this, the workflow engine needs a unique identifier for each correlation. In this sample, the unique identifier is the order number (GUID). In the first SendReplyToReceive activity, you define a CorrelationInitializer. You choose the Query Correlation Initializer query type, which means that the unique identifier is in the message that is passed to the receive activity. You also specify the xPath to the field. In addition to the Correlation Initializer, you must also specify a Correlation Handle in the CorrelateWith field. A Correlation Handle is a container for the correlation data, so the correlation data can be retrieved anywhere within the workflow. In the subsequent receives, you specify the same Correlation Handle. And in the CorrelateOn fields, you specify how to retrieve the order number from the message received.

  26. From the workflow, click the SendNotification activity, and set the following values in the Properties panel.

    Property Value

    Body

    "We have received your order.  Your order number is " + po.POID

    DisplayName

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~Order Received"

    To

    po.EmailAddress

  27. From the workflow, click the second Assign activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Assign product name

    To

    proudct

    Value

    po.Description

  28. From the workflow, click the third Assign activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Assign quantity

    To

    quantity

    Value

    po.Quantity

    You have finished implementing the Wait for order state.

  29. Under the tab name, click Order service to display the “Order service” Flowchart activity.

  30. From the workflow, double-click the Order opened Sequence activity to implement the state.

  31. Drag the following activities from Toolbox to the workflow in the order shown:

    Category Activity Note

    Primitives

    Assign

    Control Flow

    Parallel

  32. Drag the following activity inside the Parallel activity:

    Category Activity Note

    Control Flow

    Sequence

  33. Drag the following activity inside the Sequence activity:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService.Activities

    ProcessOrder

    Runtime

    Persist

    Messaging

    Receive

    Microsoft.Samples.Dublin.Tutorials.OrderService.orderWorkflowService

    SendNotification

    Primitives

    Assign

  34. Drag the following activity inside the Parallel activity and on the right of the existing Sequence activity:

    Category Activity Note

    Messaging

    ReceiveAndSendReply

    The ReceiveAndSendReply activity is a composite activity with one Sequence activity wrapping a Receive activity and a SendReplyToReceive activity.

  35. Drag the following activities inside the newly added Sequence activity and beneath the two Receive and SendReplyToReceive activities:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService.Activities

    CancelOrderProcess

    Control Flow

    If

  36. Drag the following activity inside the Then branch of the If activity:

    Category Activity Note

    Control Flow

    Sequence

  37. Drag the following activities inside the newly added Sequence activity:

    Category Activity Note

    Primitives

    Assign

    Primitives

    Assign

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService

    SenNotification

  38. Drag the following activity inside the Else branch of the If activity:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService

    SenNotification

  39. Drag the following activity inside the Parallel activity to make it the rightmost branch:

    Category Activity Note

    Messaging

    ReceiveAndSendReply

  40. Drag the following activities inside the newly added Sequence activity and beneath the two Receive and SendReplyToReceive activities:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderProcessingService.Activities

    CancelOrderProcess

    Control Flow

    If

  41. Drag the following activity inside the Then branch of the If activity:

    Category Activity Note

    Control Flow

    Sequence

  42. Drag the following activities inside the newly added Sequence activity:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService

    SenNotification

    Runtime

    TerminateWorkflow

  43. Drag the following activity inside the Else branch of the If activity:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService

    SenNotification

    The Order Opened state looks like the following after adding the activities:

    Order opened state

  44. Click the Sequence activity on the leftmost branch of the Parallel activity, and then click Variables on the bottom of the workflow to open the Variables panel.

  45. In the Variables panel, click Create Variable, and then create the following variables:

    Variable name Variable type Scope Note

    cancelOrderProcessAcknowledgement

    String

    Parallel

    ProcessServiceResult

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.ProcessServiceResult

    Sequence

    processServiceAcknowledgement

    String

    Sequence

  46. From the workflow, click the Assign activity on the top of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Initialize isUpdated

    To

    isUpdated

    Value

    False

  47. From the workflow, click the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Completion

    isUpdated Or isProcessed

    DisplayName

    Process order

  48. From the workflow, click the Sequence activity on the leftmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Processing

  49. From the workflow, click the ProcessOrder activity on the leftmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Process order

    po

    po

    ProcessOrderResult

    processServiceAcknowledgement

  50. From the workflow, click the Receive activity on the leftmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data:processServiceResult; Message type: Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.ProcessServiceResult

    DisplayName

    Receive process result

    OperationName

    SubmitProcessResult

    ServiceContractName

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService

    CanCreateInstance

    (Clear)

    CorrelationOn

    CorrelationWith: correlationOrderWorkflow; XPath Queries: key1=sm:body()/xg0:ProcessServiceResult/sg0:POID

    CorrelationWith

    correlationOrderWorkflow

  51. From the workflow, click the SendNotification activity on the leftmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Body

    "Order with order#" + po.POID + " has been processed, and is ready for shipping."

    DisplayName

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~Order Processed"

    To

    po.EmailAddress
  52. From the workflow, click the Assign activity on the leftmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Set isProcessed flag

    To

    isProcessed

    Value

    True

    You have finished configuring the leftmost branch of the Parallel activity.

  53. From the workflow, click the Sequence activity on the middle branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Waiting for update

  54. From the workflow, click the Receive activity on the middle branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data:poUpdate; Message type: Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderProcessingService.PurchaseOrder

    DisplayName

    Receive update

    OperationName

    SubmitUpdate

    ServiceContractName

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService

    CanCreateInstance

    (Clear)

    CorrelationOn

    CorrelationWith: correlationOrderWorkflow; XPath Queries: key1=sm:body()/xg0:PurchaseOrder/xg0:POID

    CorrelationWith

    correlationOrderWorkflow

  55. From the workflow, click the SendReplyToReceive activity on the middle branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data: “PO update received”; Message type: String

    DisplayName

    Acknowledge receiving update

  56. From the workflow, click the CancelOrderProcess activity on the middle branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    CancelOrderProcessResult

    cancelOrderProcessAcknowledgement

    DisplayName

    Cancel order processing

    orderID

    po.POID
  57. From the workflow, click the If activity on the middle branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Condition

    cancelOrderProcessAcknowledgement = "The order process has been terminated successfully."

    DisplayName

    Check cancellation status

  58. From the workflow, click the Sequence activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Cancellation succeed sequence

  59. From the workflow, click the first Assign activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Refresh PO

    To

    po

    Value

    poUpdate
  60. From the workflow, click the second Assign activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Set isUpdated flag

    To

    isUpdated

    Value

    True
  61. From the workflow, click the SendNotification activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    Body

    "Your order has updated upon your request. The order is under processing."

    DisplayName

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~Order Updated (by customer)"

    To

    po.EmailAddress
  62. From the workflow, click the SendNotification activity on the Else branch of the If activity, and set the following values in the Properties panel.

    Property Value

    Body

    "Your order update request cannot be processed. Please try again."

    DisplayName

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~Order Update (by customer) Failed"

    To

    po.EmailAddress

    You have finished configuring the middle branch of the Parallel activity.

  63. From the workflow, click the Sequence activity on the rightmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Waiting for cancellation

  64. From the workflow, click the Receive activity on the rightmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data:poID; Message type:String

    DisplayName

    Receive cancellation

    OperationName

    SubmitCancellation

    ServiceContractName

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService

    CanCreateInstance

    (Clear)

    CorrelationOn

    CorrelationWith: correlationOrderWorkflow; XPath Queries: key1=sm:body()/xg0:string

    CorrelationWith

    correlationOrderWorkflow

  65. From the workflow, click the SendReplyToReceive activity on the rightmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data: “PO cancellation received”; Message type: String

    DisplayName

    Acknowledge receiving cancellation

  66. From the workflow, click the CancelOrderProcess activity on the rightmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    CancelOrderProcessResult

    cancelOrderProcessAcknowledgement

    DisplayName

    Cancel order processing

    orderID

    po.POID
  67. From the workflow, click the If activity on the rightmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Condition

    cancelOrderProcessAcknowledgement = "The order process has been terminated successfully."

    DisplayName

    Check cancellation status

  68. From the workflow, click the Sequence activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Cancellation succeed sequence

  69. From the workflow, click the SendNotification activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    Body

    "Your order has been cancelled upon your request."

    DisplayName

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~Order Cancelled (by customer)"

    To

    po.EmailAddress
  70. From the workflow, click the TerminateWorkflow activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Terminate workflow

    Reason

    “Client cancellation”
  71. From the workflow, click the second SendNotification activity on the Else branch of the If activity, and set the following values in the Properties panel.

    Property Value

    Body

    "Your order cancellation request cannot be processed. Please try again."

    DisplayName

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~Order Cancellation(by customer) Failed"

    To

    po.EmailAddress

    You have finished configuring the rightmost branch of the Parallel activity.

  72. Under the tab name, click Order service to display the “Order service” Flowchart activity.

  73. From the workflow, double-click the Order processed Sequence activity to implement the state.

  74. Drag the following activities from Toolbox to the workflow in the order shown:

    Category Activity Note

    Primitives

    Assign

    Control Flow

    Parallel

  75. Drag the following activity inside the Parallel activity:

    Category Activity Note

    Control Flow

    Sequence

  76. Drag the following activity inside the Sequence activity:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.ShippingService.Activities

    ShipOrder

    Runtime

    Persist

    Messaging

    Receive

    Primitives

    Assign

  77. Drag the following activity inside the Parallel activity and on the right of the existing Sequence activity:

    Category Activity Note

    Messaging

    ReceiveAndSendReply

    The ReceiveAndSendReply activity is a composite activity with one Sequence activity wrapping a Receive activity and a SendReplyToReceive activity.

  78. Drag the following activities inside the newly added Sequence activity and beneath the two Receive and SendReplyToReceive activities:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.ShippingService.Activities

    CancelShipping

    Control Flow

    If

  79. Drag the following activity inside the Then branch of the If activity:

    Category Activity Note

    Control Flow

    Sequence

  80. Drag the following activities inside the newly added Sequence activity:

    Category Activity Note

    Primitives

    Assign

    Primitives

    Assign

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService

    SendNotification

  81. Drag the following activity inside the Else branch of the If activity:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService

    SendNotification

  82. Drag the following activity inside the Parallel activity to make it the rightmost branch:

    Category Activity Note

    Messaging

    ReceiveAndSendReply

  83. Drag the following activities inside the newly added Sequence activity and beneath the two Receive and SendReplyToReceive activities:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.ShippingService.Activities

    CancelShipping

    Control Flow

    If

  84. Drag the following activity inside the Then branch of the If activity:

    Category Activity Note

    Control Flow

    Sequence

  85. Drag the following activities inside the newly added Sequence activity:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService

    SendNotification

    Runtime

    TerminateWorkflow

  86. Drag the following activity inside the Else branch of the If activity:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService

    SenNotification

    The Order Processed state looks like the following after adding the activities:

    Order processed state

  87. Click the Sequence activity on the leftmost branch of the Parallel activity, and then click Variables on the bottom of the workflow to open the Variables panel.

  88. In the Variables panel, click Create Variable, and then create the following variables:

    Variable name Variable type Scope Note

    cancelShippingAcknowledgement

    String

    Parallel

    ShippingServiceResult

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.ShippingServiceResult

    Sequence

    shippingServiceAcknowledgement

    String

    Sequence

  89. From the workflow, click the Assign activity on the top of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Initialize isUpdated

    To

    isUpdated

    Value

    False

  90. From the workflow, click the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Completion

    isUpdated Or isShipped

    DisplayName

    Ship order

  91. From the workflow, click the Sequence activity on the leftmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Shipping

  92. From the workflow, click the ShipOrder activity on the leftmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Ship order

    poID

    po.POID

    ShipOrderResult

    shippingServiceAcknowledgement

  93. From the workflow, click the Receive activity on the leftmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data:shippingServiceResult; Message type: Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.ShippingServiceResult

    DisplayName

    Receive shipping result

    OperationName

    SubmitShippingResult

    ServiceContractName

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService

    CanCreateInstance

    (Clear)

    CorrelationOn

    CorrelationWith: correlationOrderWorkflow; XPath Queries: key1=sm:body()/xg0:ShippingServiceResult/xg0:POID

    CorrelationWith

    correlationOrderWorkflow

  94. From the workflow, click the Assign activity on the leftmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Set isShipped flag

    To

    isShipped

    Value

    True

    You have finished configuring the leftmost branch of the Parallel activity.

  95. From the workflow, click the Sequence activity on the middle branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Waiting for update

  96. From the workflow, click the Receive activity on the middle branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data:poUpdate; Message type: Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.OrderProcessingService.PurchaseOrder

    DisplayName

    Receive update

    OperationName

    SubmitUpdate

    ServiceContractName

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService

    CanCreateInstance

    (Clear)

    CorrelationOn

    CorrelationWith: correlationOrderWorkflow; XPath Queries: key1=sm:body()/xg0:PurchaseOrder/xg0:POID

    CorrelationWith

    correlationOrderWorkflow

  97. From the workflow, click the SendReplyToReceive activity on the middle branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data: “PO update received”; Message type: String

    DisplayName

    Acknowledge receiving update

  98. From the workflow, click the CancelShipping activity on the middle branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    CancelShippingResult

    cancelShippingAcknowledgement

    DisplayName

    Cancel shipping

    orderID

    poUpdate.POID
  99. From the workflow, click the If activity on the middle branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Condition

    cancelShippingAcknowledgement = "The shipping process has been terminated successfully."

    DisplayName

    Check cancellation status

  100. From the workflow, click the Sequence activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Cancellation succeed sequence

  101. From the workflow, click the first Assign activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Refresh PO

    To

    po

    Value

    poUpdate
  102. From the workflow, click the second Assign activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Set isUpdated flag

    To

    isUpdated

    Value

    True
  103. From the workflow, click the SendNotification activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    Body

    "Your order has updated upon your request. The order is under processing."

    DisplayName

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~Order Updated (by customer)"

    To

    po.EmailAddress
  104. From the workflow, click the SendNotification activity on the Else branch of the If activity, and set the following values in the Properties panel.

    Property Value

    Body

    "Your order update request cannot be processed. The order has been shipped."

    DisplayName

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~Order Update (by customer) Failed"

    To

    po.EmailAddress

    You have finished configuring the middle branch of the Parallel activity.

  105. From the workflow, click the Sequence activity on the rightmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Waiting for cancellation

  106. From the workflow, click the Receive activity on the rightmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data:poID; Message type:String

    DisplayName

    Receive cancellation

    OperationName

    SubmitCancellation

    ServiceContractName

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService.IOrderWorkflowService

    CanCreateInstance

    (Clear)

    CorrelationOn

    CorrelationWith: correlationOrderWorkflow; XPath Queries: key1=sm:body()/xg0:string

    CorrelationWith

    correlationOrderWorkflow

  107. From the workflow, click the SendReplyToReceive activity on the rightmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Content

    Message; Message data: “PO cancellation received”; Message type: String

    DisplayName

    Acknowledge receiving cancellation

  108. From the workflow, click the CancelShipping activity on the rightmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    CancelshippingResult

    cancelShippingAcknowledgement

    DisplayName

    Cancel shipping

    poID

    po.POID
  109. From the workflow, click the If activity on the rightmost branch of the Parallel activity, and set the following values in the Properties panel.

    Property Value

    Condition

    cancelShippingAcknowledgement = "The shipping process has been terminated successfully."

    DisplayName

    Check cancellation status

  110. From the workflow, click the Sequence activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Cancellation succeed sequence

  111. From the workflow, click the SendNotification activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    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

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~Order Cancelled (by cusotmer)"

    To

    po.EmailAddress
  112. From the workflow, click the TerminateWorkflow activity on the Then branch of the If activity, and set the following values in the Properties panel.

    Property Value

    DisplayName

    Terminate workflow

    Reason

    “Client cancellation”
  113. From the workflow, click the second SendNotification activity on the Else branch of the If activity, and set the following values in the Properties panel.

    Property Value

    Body

    "Your order cancellation request cannot be processed. The order has been shipped.

    DisplayName

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~Order Cancellation(by customer) Failed"

    To

    po.EmailAddress

    You have finished configuring the rightmost branch of the Parallel activity.

  114. Under the tab name, click Order service to display the “Order service” Flowchart activity.

  115. From the workflow, double-click the Order completed Sequence activity to implement the state.

  116. Drag the following activities from Toolbox to the workflow in the order as shown:

    Category Activity Note

    Microsoft.Samples.Dublin.Tutorials.OrderService.OrderWorkflowService

    SendNotification

  117. From the workflow, click the second SendNotification activity on the Else branch of the If activity, and set the following values in the Properties panel.

    Property Value

    Body

    "Your order has been shipped.  Thank you for shopping at contoso.com."

    DisplayName

    Send client notification

    Subject

    "Contoso.com Order#" + po.POID + "~~ Order Shipped"

    To

    po.EmailAddress

    You have finished the workflow development.

In this configuration file, you define two endpoints and one behavior element.

To configure the Order Workflow service by using a configuration file

  1. From Solution Explorer, expand OrderWorkflowService, and then double-click Web.config to open it.

  2. Add a <services> tag inside the <system.serviceModel> tag.

        <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>
    

To compile the Order Workflow service

  1. From Solution Explorer, right-click the OrderWorkflowService project, and then click Rebuild. Make sure the project is compiled successfully in the Output window.

Finishing the Order Processing service

OrderProcessingService and OrderWorkflowService reference each other. So you have to finish OrderProcessingService after finishing OrderWorkflowService.

To add the service references

  1. From Solution Explorer, right-click OrderProcessingService, and then click Add Service Reference.

  2. From Add Service Reference, click Discover. Visual Studio should discover both of the services.

  3. Enter and select the following values, and then click OK to create the service reference.

    Property Value

    Services

    OrderWorkflow.xamlx

    Namespace

    OrderWorkflowService

To modify OrderProcess.svc

  1. From Solution Explorer, expand OrderProcessingService, and then double-click OrderProcessing.svc to open it.

  2. Uncomment the section inside the SendProcessResult function, so the function looks like:

    
    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);
        }
    
    }
    

To compile the Order Processing service

  1. From Solution Explorer, right-click the OrderProcessingService project, and then click Rebuild. Make sure the project is compiled successfully in the Output window.

Finishing the Shipping service

ShippingService and OrderWorkflowService reference each other. So you have to finish ShipingService after finishing OrderWorkflowService.

To add the service references

  1. From Solution Explorer, right-click ShippingService, and then click Add Service Reference.

  2. From Add Service Reference, click Discover. Visual Studio should discover both of the services.

  3. Enter and select the following values, and then click OK to create the service reference.

    Property Value

    Services

    OrderWorkflow.xamlx

    Namespace

    OrderWorkflowService

To modify Shipping.svc

  1. From Solution Explorer, expand ShippingService, and then double-click Shipping.svc to open it.

  2. Uncomment the section inside the SendShippingResult function, so the function looks like:

    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);
        }
    }
    

To compile the Shipping service

  1. From Solution Explorer, right-click the ShippingService project, and then click Rebuild. Make sure the project is compiled successfully in the Output window.

Developing the Order Client Application

In this step, you develop a Windows Form client application.

To add a Windows Form application project to the solution

  1. From Solution Explorer, right-click Solution ‘OrderService’, point to Add, and then click New Project.

  2. From Add New Project, choose or type the following values, and then click OK.

    Property Value

    Project types

    Visual C#/Windows

    Templates

    Windows Forms Application

    Name

    OrderClient

    Location

    C:\DublinTutorial\OrderServiceSolution\OrderService

The Order client is an interface to the workflow service. You must add a service reference to the workflow service.

To add the service reference

  1. From Solution Explorer, right-click OrderClient, and then click Add Service Reference to open the Add Service Reference dialog box.

  2. From Add Service Reference, click Discover.

  3. Enter and select the following values, and then click OK to create the service reference.

    Property Value

    Services

    OrderWorkflow.xamlx

    Namespace

    OrderWorkflowService

To develop the Windows Form

  1. From Solution Explorer, expand OrderClient, and then double-click Form1.cs to open it.

  2. Right-click Form1.cs, click Rename, and then type OrderForm.cs.

  3. Click Yes on the prompt.

  4. From the Toolbox, add the four Label controls, five TextBox controls, and three Button controls to the form.

  5. From the workflow, click the form, and set the following values in the Properties panel.

    Property Value

    Name

    OrderForm

    Text

    Contoso.com Order Form

  6. From the workflow, click label1, and set the following values in the Properties panel.

    Property Value

    Name

    lblOrderNumber

    Text

    Order number:

  7. From the workflow, click label2, and set the following values in the Properties panel.

    Property Value

    Name

    lblEmail

    Text

    Email:

  8. From the workflow, click label3, and set the following values in the Properties panel.

    Property Value

    Name

    lblDescription

    Text

    Description:

  9. From the workflow, click label4, and set the following values in the Properties panel.

    Property Value

    Name

    lblQuantity

    Text

    Quantity:

  10. From the workflow, click textbox1, and set the following values in the Properties panel.

    Property Value

    Name

    txtOrderNumber

    Enabled

    False

  11. From the workflow, click textbox2, and set the following values in the Properties panel.

    Property Value

    Name

    txtEmail

    Text

    JohnDole@fabrikam.com

  12. From the workflow, click textbox3, and set the following values in the Properties panel.

    Property Value

    Name

    txtDescription

    Text

    Windows 7

  13. From the workflow, click textbox4, and set the following values in the Properties panel.

    Property Value

    Name

    txtQuantity

    Text

    10

  14. From the workflow, click textbox5, and set the following values in the Properties panel.

    Property Value

    Name

    txtStatus

    Anchor

    Bottom, Left, Right

    Enabled

    False

    Text

    “”

  15. From the workflow, click button1, and set the following values in the Properties panel.

    Property Value

    Name

    btnSubmit

    Anchor

    Bottom, Right

    Text

    Submit

    Click (Under the Event tab)

    btnSubmit_Click

  16. From the workflow, click button2, and set the following values in the Properties panel.

    Property Value

    Name

    btnUpdate

    Anchor

    Bottom, Right

    Text

    Update

    Click (Under the Event tab)

    btnUpdate_Click

  17. From the workflow, click button3, and set the following values in the Properties panel.

    Property Value

    Name

    btnCancel

    Anchor

    Bottom, Right

    Text

    Cancel

    Click (Under the Event tab)

    btnCancel_Click

  18. From Solution Explorer, right-click OrderForm.cs, and then click View Code.

  19. Right-click the OrderClient namespace, click Refactor, and then click Rename to open the Rename dialog box.

  20. From Rename, type Microsoft.Samples.Dublin.Tutorials.OrderService.OrderClient, and then click OK.

  21. Click Apply.

  22. Replace the code with the following:

    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
        }
    }
    

To compile the Order client

  1. From Solution Explorer, right-click the OrderClient project, and then click Rebuild. Make sure the project is compiled successfully in the Output window.

Testing the Order Service

To test the Order service

  1. From Solution Explorer, right-click OrderClient, and then click Set as StartUp Project.

  2. From Visual Studio, click the Debug menu, and then click Start Debugging. You should see a Windows Form opened.

  3. From the form, click Submit.

  4. Open Windows Explorer, and browse to the C:\DublinTutorial\Inbox folder.

  5. Wait until you see all three e-mail notifications. It takes about three to four minutes to see all three files.

Packaging the Order Service

To package the OrderProcessingService WCF service

  1. From Solution Explorer, right-click the OrderProcessingService project, and then click Package/Publish Settings.

  2. Enter the following values:

    Property Value

    Create web package as a ZIP file

    (selected)

    Location where the package will be created

    C:\DublinTutorial\DeploymentPackages\OrderProcessingService.zip

    IIS Web Site/Application name to be used on the destination server

    OrderService/OrderProcessingService

  3. From Solution Explorer, right-click the OrderProcessingService project, and then click Create Package.

  4. Repeat the last procedure to create packages for the other three projects with the following settings:

    Project name Location where the package will be created IIS Web Site/Application name to be used on the destination server

    OrderWorkflowService

    C:\DublinTutorial\DeploymentPackages\OrderWorkflowService.zip

    OrderService/OrderWorkflowService

    ShippingService

    C:\DublinTutorial\DeploymentPackages\ShippingService.zip

    OrderService/ShippingService

    Note

    You might consider updating the endpoint addresses of the dependent services in the Web.config files to reflect the server where the packages will be deployed before packaging a service.

See Also

Concepts

Tutorial Using the AppFabric Interface
Tutorial Using Windows PowerShell

  2012-09-12