Building a declarative WCF service using Workflow Foundation 4 and Content Based Correlation

This blog post accompanies my session on Workflow Foundation 4 programming during the Belgian Tech Days (actually developers and IT-pro days :)). During this session I built a WCF service using Workflow Foundation 4, and I want to show you how to do this on your own…

In the first part you’ll learn how to create a simple FlowChart workflow and test it, and then in the second part you’ll learn how to setup correlation so multiple players can play the game…

Preparing the lab

This lab starts with a new project, so start Visual Studio 2010 and create a new workflow service project (call it NumberGuessingGame):

image

This creates a new solution with a workflow project.

image

Remove Service1.xamlx, we’re going to add a new service with a better name.

Right-click the project and add a new item. Select the WCF Workflow Service template and name it GuessIt.xamlx.

Creating the initial FlowChart

This adds a workflow service with a sequential activity containing a Receive and Send activity. Delete the sequential activity leaving the workflow empty. Open the toolbox and drag a FlowChart activity onto the workflow designer. This should look like this now:

image

Next drag a Receive activity onto the designer, below Start. Name it Start A New Game. Select the receive activity and enter following the OperationName, ServiceContractName and CanCreateInstance properties in the properties window:

image

Next right-click on the receive activity and select the Create SendReply option from the drop-down menu. This add a Send activity to the workflow. The Send is coupled to the receive activity through its Request property:

image

Now connect the activities:

image

Adding variables

Now, in the workflow designer open the variables window and add a new variable called player of type String. This will hold the player name received through the “Start A New Game” Receive activity. You will also see a variable of type CorrelationHandle. This is used to connect several receive and send activities through correlation. Rename this to gameHandle.We’ll use this handle later to setup content-based correlation.

Now add two new variables theNumber and guess, both of type Int32. The first is the number the user needs to guess, to you need to initialize it to a random number between 0 and 100. Use the Random type to do this:

image

Go back to the first receive activity. Click on the content property. This opens the Content Definition window. Select the player as the message data (and set the Message type to String):

image

Do the same for the send activity, but now use following expression (of type String):

   1: player + " guess the number between 0 and 100"

You might also get validation errors because you renamed the correlation handle to gameHandle. Change the CorrelationInitilizers property to use gameHandle (click on the … button).

image

Testing the service

Press F5 in Visual Studio. The WCF Test Client will start and automatically fetch meta-data from the service. Double click the Begin method. This opens a new tab allowing you to invoke the Begin operation on the service. Enter your name and click Invoke. In the bottom area you should see the result of invoking the begin method.

image

This concludes the first step.

Adding the data contracts

Let’s add a couple of data contracts to the project, one for a game and another for a guess. Note that both contain the player name, this way our service will be able to distinguish between multiple games, as long as each player uses a unique player name:

   1: [DataContract]
   2:  
   3: public class Game
   4:  
   5: {
   6:  
   7: [DataMember]
   8:  
   9: public string PlayerName { get; set; }
  10:  
  11: [DataMember]
  12:  
  13: public string Message { get; set; }
  14:  
  15: }
  16:  
  17: [DataContract]
  18:  
  19: public class Guess
  20:  
  21: {
  22:  
  23: [DataMember(IsRequired = true)]
  24:  
  25: public string PlayerName { get; set; }
  26:  
  27: [DataMember(IsRequired = true)]
  28:  
  29: public int Try { get; set; }
  30:  
  31: }

Make the “Send Game Started” send activity use a Game instance as the result. To do this you will need to add another variable of type Game, and initialize it to a new instance:

image

Now add to assign activities after the Begin receive activity, and assign appropriate values to the game:

image

Adding the guessing logic

Add another variable, calling it guess of type Guess. Then add another receive activity after the send activity, but now with an operation name called Guess, taking guess variable as its content. Check if the guess was right using a decision shape. If so, congratulate the user. If not, decide whether the guess was too small or large. Confirm this back to the user using three SendReply activities (create each one by right-clicking the Guess receive activity and select Create SendReply).

Here is an example of the result:

image

Adding Content-based Correlation

Of course we want to make a single player play the same game, but what if multiple players are playing on the same server? We need correlation. In this part we’re going to correlate the guess activity to the Begin activity using the player’s name. That is why our data contract both contain the player’s name (by coincidence the properties have the same name, but this is not required).

To do correlation we need a correlation handle. This handle will act like a key to a workflow. If a request comes in, we’re going to find this key through part of the message, in our case the player’s name. So, if you haven’t done so, add a new variable to the workflow called gameHandle of type CorrelationHandle. The make sure that all the first sendReply activity is set to initialize this handle by ensuring the CorrelationInitializer is set like this:

image

When the workflow sends this message, we’re saying that the key of the gameHandle is the player’s name. So when another message arrives, the workflow runtime can then see is the message contains a valid key (again the player’s name), use this key to find the right workflow instance, and then send the message to it. So next step is to set the Guess receive activity’s Correlates On like this:

image

Now you should be able to play a game, making sure that the first and following messages all have the same player name. You can also start two or more games, each with their own player name!