Conversations Sample

Download sample

This sample shows how a workflow service can have parallel conversations with multiple clients over the same contract. The sample shows how to correlate messages that are sent for the same contract and same operation but which must be handled differently because they are sent by different clients. To achieve parallel conversations, this sample uses the conversation context functionality provided by workflow services.

Note

This sample requires that .NET Framework version 3.5 is installed to build and run. Visual Studio 2008 is required to open the project and solution files.

For more information about setting up this sample, see One-Time Set Up Procedure for the Windows Communication Foundation Samples.

This sample also uses asynchronous duplex communication so that the workflow service and the client can asynchronously communicate. In duplex communication, the two applications must exchange a context before communication begins. The service that initiates the conversation receives the context in the reply to its message. Workflow services provides this functionality. To support the communication from the receiving service to the initiating service, the initiating service must send its context information in the first message. The architecture of the sample is shown in the following illustration.

Conversations Sample Architecture

Conversations Sample

This sample implements the following scenario.

A customer sends a request for an order. In response to this, the supplier wants to obtain quotes from three different logistics providers to ship the order. The supplier sends a message to all the three suppliers. Each of the providers sends a quote back by invoking the same operation on the same contract. Because the supplier workflow uses the conversation context, functionality can correlate the quotes to the correct receive activity to further process them. The supplier receives all the quotes, picks the lowest one, and sends it to the customer.

Five entities communicate in this sample:

  • Customer service

    The customer service sends the order details to the supplier, along with a context that the supplier service uses later to communicate back to the customer service. This basic workflow contains an initial Send activity, which sends the purchase order request message with the purchase order and the context as payloads. A Receive activity waits for a response from the supplier service.

    The context that the customer service sends is associated with the Receive activity. The "before send" handler of the Send activity contains code that obtains the context from the Receive activity. The Receive activity includes the following GetContext method that is called to obtain the context.

    private void PrepareOrder(object sender, SendActivityEventArgs e)
    {
        this.order.Amount = 1000;
        this.order.OrderId = 1234;
        this.contextToSend = this.ReceiveOrderDetails.Context;
    }
    
  • Supplier service

    The supplier service communicates with three logistics providers. To do this, it uses a combination of a unique context token for each conversation and asynchronous duplex communication. It sends the context in the message body of the communication between the customer and supplier services.

    Before communicating with the logistics providers, the supplier service first receives the message from the customer service. In this message, the supplier service also receives the context that it uses to communicate back with the customer service. The supplier service workflow applies this context to the Send activity that is used to send a message to the client service. The code that implements this functionality is in the code handler of the Code activity inside the first Receive activity, as shown in the following code.

    private void AcceptOrder(object sender, EventArgs e)
    {
        Console.WriteLine("Order Received...");
        this.supplierAck = "Order Received on " + DateTime.Now;
        this.SendOrderDetails.Context = this.customerContext;
    }
    

    Once the supplier service receives a message from the customer, the supplier initiates three parallel conversations with the three logistics providers. Each conversation branch has a Send and a Receive activity, as shown in the previous illustration. The Send activities in each branch send the message to one logistics supplier. The corresponding Receive activity in that branch must retrieve the message from the supplier. To do so, the Send activity in the message payload must send a unique context in the payload. The logistics provider then uses this context in the message header when it sends back the message with the quote.

    By default, every Receive activity has a root context. To make the Receive activity unique, the Receive activity defines a context that is scoped to a parent activity other than the root activity. In the following sample, the context token property of each Receive activity in the parallel conversation has a unique name and is scoped to the parallel activity in which it is contained. When the Send activity within each of the parallel branches obtains a context from the Receive activity, it obtains a context that is unique to that Receive activity. This unique context is also used to create a queue name for the queue on which the Receive activity is listening. When the logistics provider sends the quote back with the context in the header, the workflow service dispatch layer uses it to create the appropriate queue name and queue the message, which the Receive activity then looks at.

    private void PrepareShipper2Request(object sender, SendActivityEventArgs e)

    {

    Console.ForegroundColor = ConsoleColor.Green;

    Console.WriteLine("RequestShippingQuote from Shipper2");

    Console.ResetColor();

    this.contextShipper2 = this.ReceiveQuoteFromShipper2.Context;

    }

    The logistics provider workflows receive the quote request from the supplier, along with the context. That context is applied to the Send activity that sends the message back to the supplier, as the following code shows.

    private void AcceptQuoteRequest(object sender, EventArgs e)
    {
        Console.ForegroundColor = ConsoleColor.White;
        Console.WriteLine("Received ShippingQuote Request");
        this.supplierAck = "Working on quote...";
        Console.ResetColor();
        this.SendShippingQuote.Context(this.supplierContext);
    }
    

To set up, build, and run the sample

  1. By default, this sample does not use persistence. If you want persistence, you must add the <WorkflowRuntime> entry in the App.config file for each of the solutions. The entry should be under the behaviors section, as demonstrated in the following example.

    <behaviors>
          <serviceBehaviors>
            <behavior name="ServiceBehavior"  >
              <serviceMetadata httpGetEnabled="false" />
              <serviceDebug includeExceptionDetailInFaults="true" />
              <workflowRuntime name="WorkflowServiceHostRuntime" validateOnCreate="true" enablePerformanceCounters="true">
                <services>
                  <add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                       connectionString="Data Source=localhost\sqlexpress;Initial Catalog=ServiceModelSamples_ServiceWorkflowStore;Integrated Security=True;Pooling=False"
                       LoadIntervalSeconds="1" UnLoadOnIdle= "true" />
                </services>
              </workflowRuntime>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    
  2. In addition to the <WorkflowRuntime> entry under the behaviors section, a SQL Persistence Service is also added. Run the CreateStores.cmd script located in the One-Time Set Up Procedure for the Windows Communication Foundation Samples topic. The CreateStores.cmd script creates the ServiceModelSamples_ServiceWorkflowStore database. By default, these databases are created in a SQL Server 2005 Express Edition database. Make sure you have SQL Server Express installed on your computer. If you do not want to install SQL Server Express and prefer to use SQL Server instead, make sure to modify the connection strings in the App.config files for the persistence databases.

  3. Once all the workflow services are running, press ENTER in the client workflow to view all the workflows communicating with each other. The purchase order is sent to the supplier who, in turn, sends logistics quote requests to all the logistics suppliers. Once the supplier receives quotes, you can see that the lowest quote is sent back to the customer. You can also verify the context tokens in each case. This helps to understand the unique contexts that are sent to each logistics provider.

© 2007 Microsoft Corporation. All rights reserved.