Continuing on from Part 1 now we are going to add the Calculation operations to our stateful workflow service. First we need to look back and understand our previous operation “Start”.
If you look at the Receive activity for the Start operation you will see that it has a property in the properties panel (F4) called CanCreateInstance and it is set to true. This property means that a call to this operation will start a new instance of our workflow. Up to now our service has simply started when we called the “Start” method and ended after the response was sent. This is all well and good but as I stated above we want a stateful service that will track the current value of our operations and let us perform further operations in a chaining manner. To do this our Add, Subtract, Divide and Multiply operations are not going to create new instances but simply act upon the previous return value.
This poses a problem, if we can call the start operation multiple times and create multiple instance how are we going to know which instance we want when we make the subsequent calculation operations? This is where correlation comes in. Correlation is simply the method by which we direct incoming messages to the correct workflow instance. In our example we are going to use a parameter on each operation called session name. This will allow us to tag the session with a name so that we can bring up the right instance when we make subsequent calls. First we are going to need a CorrelationHandle. This is a special type provided by workflow which allows us to create this token so that the runtime can correlate properly.
1. At the root sequence (Sequential Service), add a variable of type System.ServiceModel.Activities.CorrelationHandle called “SessionNameCorrelationHandle”. You do not need to default this variable, any type that derives from System.Activities.Handle will be constructed automatically by the runtime.
2. Also at the root sequence add another variable called “SessionName” of type string. This is going to hold the actual session name specified on the Start operation.
3. Edit the Content for the ReceiveRequest activity and add a parameter called “sessionName” of type string and assign it to the variable “SessionName”.
Now we need to initialize our correlation handle on the Start operation.
4. On the send reply activity add another return parameter called “SessionReturn” which returns our SessionName variable.
5. Also on the send reply activity, from the properties panel choose CorrelationInitializers, add the initializer to our SessionNameCorrelationHandle on the left. On the right make sure you have “Query Correlation Initializer” selected which will allow us to choose a value from the result to initialize the correlation handle.From the drop down under XPath Queries choose our SessionReturn parameter.
You do not have to use this method to initialize the correlation handle. You could also use the InitializeCorrelation activity and place it after the SendReply activity, initializing from the “SessionName” variable rather than the return parameter.
Next we need to add our calculation operations which can be performed as many times as we want until we choose to end the session. To do this we are going to use a Pick activity to host 4 Receive and SendReply pairs (Add, Subtract, Divide, Multiply). The Pick activity is kind of like a parallel which contains multiple Pick Branches. Each Branch has a trigger and an action. Once the trigger in a branch has been satisfied the other branches are all cancelled and the action for the triggered branch is executed. We are going to use the Trigger part of each branch to host an infinite loop of the Receive/SendReply pairs so that they continue to accept subsequent calls.A final Pick branch will contain the End operation which will Stop the Calculator session and free up the correlation handle.
6. Add a Pick activity at the end of our current workflow. Rename Branch1 to “Add Branch” by changing the title.Drag a While activity into the Trigger of "Add Branch”, set the condition to True so that it repeats indefinitely.
7. Drag a ReceiveAndSendReply from the toolbox into the While activity’s Body, change the operation name to “Add”. In the sequence created by the ReceiveAndSendReply add an Int32 variable called X. Change the content of the Receive(Add)to Parameters with an Int32 parameter called X and a string parameter called SessionName. Assign the X parameter to our X variable.
8. To setup the correlation click on the CorrelatesOn property in the properties panel (F4) of the Receive(Add) activity. Change the CorrelatesWith to point to our SessionNameCorrelationHandle. Choose the property SessionName. Make sure the Key matches the key used in step 5.
9. In between the Receive(Add) and it’s SendReply activity drag an Assign activity. In the To section enter the Value variable and in the right hand side enter the expression “Value + X”.
10. On the SendReplyToReceive of the Add pair change the content to return parameters with a single parameter Result with a value of our Value variable.
11. Delete Branch2 from the pick and lets test what we have with CTRL+F5. Open the Start operation and enter an integer value and a string session name then invoke. Open the Add method and repeat the same name with another integer.
12. Now Copy and paste the Add branch to create a Subtract, Divide and Multiply branches changing the operation names and assign activities as necessary. Note that you will need to go into each branch and change the CorrelatesOn property of each Receive activity so that the XPath is correct and not pointing to the Add method. Also remember to keep the Key the same as step 5. You will need to use the “\” integer divide operator of VB to do the divide assign statement.
13. Finally we need to add a branch for our end activity. This will be another Pick branch but this time there will be no While loop so that when it gets called, the other branches will get cancelled and the workflow will complete. Drag on a new PickBranch, Drag a ReceiveAndSendReply into the trigger, change the operation name, add the SessionName parameter to the content and set the correlation like the others.
So now we have created our stateful service with correlation on a session name. You should note that you cannot use the session name after calling End just like you could not use a random new session name on any operation but Start.
In the next part we will look at what happens in the service host to enable these services endpoints to be created.
Code for this post is attached below.