With WF4 it is quite easy to use data that is part of the request message, for example an order identifier, to route multiple WCF messages to the same workflow. It is also possible to have multiple messages that can start a new workflow. In this blog post I am going to show both these concepts in a single workflow. This workflow is going to be able to receive three different messages, AddItem, AddExpensiveItem and Submit.  Either AddItem or AddExpensiveItem can start a new workflow while Submit can only be done with an existing workflow.

The final workflow looks like this%u00b1

 

To create the workflow you need to start by creating a new WCF Workflow Service Application in Visual Studio 2010. Next delete the default activities that have been created by the template and replace it with a Sequence activity. Add a variable named TotalAmount of type Int32 and a Boolean variable named OrderSubmitted. Add a DoWhile activity and set its condition to OrderSubmitted = false so it will keep on executing until we set the OrderSubmitted variable to true.

So much for the boring part, now we get to the real message part.

First we need to add a Pick activity. This is needed because we want to receive multiple different messages without specifying an order. Add a third PickBrach so we get a total of three branches and a a Receive activity to each Trigger. Set all three ServiceContractName’s to OrderService and set the OperationName to AddItem, AddExpensiveItem and Submit respectively. Now the AddItem and AddExpensiveItem requests are allowed to start a new workflow so check the CanCreateInstance for both of them.

Next the important part for the correlation bit. All three requests need to share some common piece of data.Below is the Content definition of the AddItem request.

Both the AddExpensiveItem and Submit requests only contain the orderId parameter

The important is that they all share the same orderId that the client needs to provide.

 

That takes care of sending some common data but we still need to configure the workflow to use that to correlate requests to the same workflow. This last part is done using the CorrelatesOn property of the Receive activity. In all three point this to the orderId being passed in and make sure all three have a matching key.

 

After we have added the processing part to the Action part of each PickBranch we are all set to go.

Note: to create the SendReply, just right click the Receive activity and select Create SendReply. This will be placed on the clipboard so now you can paste it into the Action Sequence.

 

Running the workflow

Press F5 to activate the WCF Test Client. You should see three possible actions, either AddItem or AddExpensiveItem can start a workflow or send messages to an existing workflow. It just depends on whether the orderId passed in can be correlated to an existing workflow. If so that workflow receives the message, otherwise a new workflow is started.

The Submit message on the other hand can only be executed with an existing workflow.

 

 

Just in case anyone is interested below is the complete XAML for the workflow:

<WorkflowService mc:Ignorable="sap" ConfigurationName="Service1" sap:VirtualizedContainerService.HintSize="1193,850" Name="Service1" mva:VisualBasic.Settings="Assembly references and imported namespaces serialized as XML namespaces" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/servicemodel" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="clr-namespace:Microsoft.VisualBasic;assembly=System" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:p="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:s1="clr-namespace:System;assembly=System" xmlns:s2="clr-namespace:System;assembly=System.Xml" xmlns:s3="clr-namespace:System;assembly=System.Core" xmlns:s4="clr-namespace:System;assembly=System.ServiceModel" xmlns:sa="clr-namespace:System.Activities;assembly=System.Activities" xmlns:sad="clr-namespace:System.Activities.Debugger;assembly=System.Activities" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=System" xmlns:scg1="clr-namespace:System.Collections.Generic;assembly=System.ServiceModel" xmlns:scg2="clr-namespace:System.Collections.Generic;assembly=System.Core" xmlns:scg3="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:sd="clr-namespace:System.Data;assembly=System.Data" xmlns:sl="clr-namespace:System.Linq;assembly=System.Core" xmlns:ssa="clr-namespace:System.ServiceModel.Activities;assembly=System.ServiceModel.Activities" xmlns:ssx="clr-namespace:System.ServiceModel.XamlIntegration;assembly=System.ServiceModel" xmlns:st="clr-namespace:System.Text;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <p:Sequence sad:XamlDebuggerXmlReader.FileName="c:\users\maurice\documents\visual studio 2010\Projects\DeclarativeServiceLibrary1\DeclarativeServiceLibrary1\Service1.xamlx" sap:VirtualizedContainerService.HintSize="1163,820" mva:VisualBasic.Settings="Assembly references and imported namespaces serialized as XML namespaces">
    <p:Sequence.Variables>
      <p:Variable x:TypeArguments="x:Int32" Name="TotalAmount" />
    </p:Sequence.Variables>
    <sap:WorkflowViewStateService.ViewState>
      <scg3:Dictionary x:TypeArguments="x:String, x:Object">
        <x:Boolean x:Key="IsExpanded">True</x:Boolean>
      </scg3:Dictionary>
    </sap:WorkflowViewStateService.ViewState>
    <p:DoWhile sap:VirtualizedContainerService.HintSize="1141,696">
      <p:DoWhile.Variables>
        <p:Variable x:TypeArguments="x:Boolean" Name="OrderSubmitted" />
      </p:DoWhile.Variables>
      <p:DoWhile.Condition>[OrderSubmitted = False]</p:DoWhile.Condition>
      <p:Pick sap:VirtualizedContainerService.HintSize="1115,576">
        <p:PickBranch DisplayName="Branch1" sap:VirtualizedContainerService.HintSize="307,530">
          <p:PickBranch.Variables>
            <p:Variable x:TypeArguments="CorrelationHandle" Name="__handle1" />
            <p:Variable x:TypeArguments="x:Int32" Name="Price" />
          </p:PickBranch.Variables>
          <p:PickBranch.Trigger>
            <x:Reference>__ReferenceID0</x:Reference>
          </p:PickBranch.Trigger>
          <p:Sequence sap:VirtualizedContainerService.HintSize="277,312">
            <sap:WorkflowViewStateService.ViewState>
              <scg3:Dictionary x:TypeArguments="x:String, x:Object">
                <x:Boolean x:Key="IsExpanded">True</x:Boolean>
              </scg3:Dictionary>
            </sap:WorkflowViewStateService.ViewState>
            <p:Assign sap:VirtualizedContainerService.HintSize="255,58">
              <p:Assign.To>
                <p:OutArgument x:TypeArguments="x:Int32">[TotalAmount]</p:OutArgument>
              </p:Assign.To>
              <p:Assign.Value>
                <p:InArgument x:TypeArguments="x:Int32">[TotalAmount + Price]</p:InArgument>
              </p:Assign.Value>
            </p:Assign>
            <SendReply DisplayName="SendReplyToReceive" sap:VirtualizedContainerService.HintSize="255,90">
              <SendReply.Request>
                <Receive x:Name="__ReferenceID0" CanCreateInstance="True" sap:VirtualizedContainerService.HintSize="277,100" OperationName="AddItem" ServiceContractName="OrderService">
                  <Receive.CorrelatesOn>
                    <XPathMessageQuery x:Key="key1">
                      <XPathMessageQuery.Namespaces>
                        <ssx:XPathMessageContextMarkup>
                          <x:String x:Key="xgSc">http://tempuri.org/</x:String>
                        </ssx:XPathMessageContextMarkup>
                      </XPathMessageQuery.Namespaces>sm:body()/xgSc:AddItem/xgSc:orderId</XPathMessageQuery>
                  </Receive.CorrelatesOn>
                  <Receive.CorrelationInitializers>
                    <RequestReplyCorrelationInitializer CorrelationHandle="[__handle1]" />
                  </Receive.CorrelationInitializers>
                  <ReceiveParametersContent>
                    <p:OutArgument x:TypeArguments="x:Int32" x:Key="orderId" />
                    <p:OutArgument x:TypeArguments="x:String" x:Key="item" />
                    <p:OutArgument x:TypeArguments="x:Int32" x:Key="price">[Price]</p:OutArgument>
                  </ReceiveParametersContent>
                </Receive>
              </SendReply.Request>
              <SendParametersContent>
                <p:InArgument x:TypeArguments="x:Int32" x:Key="Total">[TotalAmount]</p:InArgument>
              </SendParametersContent>
            </SendReply>
          </p:Sequence>
        </p:PickBranch>
        <p:PickBranch sap:VirtualizedContainerService.HintSize="307,530">
          <p:PickBranch.Variables>
            <p:Variable x:TypeArguments="CorrelationHandle" Name="__handle1" />
          </p:PickBranch.Variables>
          <p:PickBranch.Trigger>
            <x:Reference>__ReferenceID1</x:Reference>
          </p:PickBranch.Trigger>
          <p:Sequence sap:VirtualizedContainerService.HintSize="277,312">
            <sap:WorkflowViewStateService.ViewState>
              <scg3:Dictionary x:TypeArguments="x:String, x:Object">
                <x:Boolean x:Key="IsExpanded">True</x:Boolean>
              </scg3:Dictionary>
            </sap:WorkflowViewStateService.ViewState>
            <p:Assign sap:VirtualizedContainerService.HintSize="255,58">
              <p:Assign.To>
                <p:OutArgument x:TypeArguments="x:Int32">[TotalAmount]</p:OutArgument>
              </p:Assign.To>
              <p:Assign.Value>
                <p:InArgument x:TypeArguments="x:Int32">[TotalAmount + 100]</p:InArgument>
              </p:Assign.Value>
            </p:Assign>
            <SendReply DisplayName="SendReplyToReceive" sap:VirtualizedContainerService.HintSize="255,90">
              <SendReply.Request>
                <Receive x:Name="__ReferenceID1" CanCreateInstance="True" sap:VirtualizedContainerService.HintSize="277,100" OperationName="AddExpensiveItem" ServiceContractName="OrderService">
                  <Receive.CorrelatesOn>
                    <XPathMessageQuery x:Key="key1">
                      <XPathMessageQuery.Namespaces>
                        <ssx:XPathMessageContextMarkup>
                          <x:String x:Key="xgSc">http://tempuri.org/</x:String>
                        </ssx:XPathMessageContextMarkup>
                      </XPathMessageQuery.Namespaces>sm:body()/xgSc:AddExpensiveItem/xgSc:orderId</XPathMessageQuery>
                  </Receive.CorrelatesOn>
                  <Receive.CorrelationInitializers>
                    <RequestReplyCorrelationInitializer CorrelationHandle="[__handle1]" />
                  </Receive.CorrelationInitializers>
                  <ReceiveParametersContent>
                    <p:OutArgument x:TypeArguments="x:Int32" x:Key="orderId" />
                  </ReceiveParametersContent>
                </Receive>
              </SendReply.Request>
              <SendParametersContent>
                <p:InArgument x:TypeArguments="x:Int32" x:Key="Total">[TotalAmount]</p:InArgument>
              </SendParametersContent>
            </SendReply>
          </p:Sequence>
        </p:PickBranch>
        <p:PickBranch DisplayName="Branch2" sap:VirtualizedContainerService.HintSize="307,530">
          <p:PickBranch.Variables>
            <p:Variable x:TypeArguments="CorrelationHandle" Name="__handle2" />
          </p:PickBranch.Variables>
          <p:PickBranch.Trigger>
            <x:Reference>__ReferenceID2</x:Reference>
          </p:PickBranch.Trigger>
          <p:Sequence sap:VirtualizedContainerService.HintSize="277,312">
            <sap:WorkflowViewStateService.ViewState>
              <scg3:Dictionary x:TypeArguments="x:String, x:Object">
                <x:Boolean x:Key="IsExpanded">True</x:Boolean>
              </scg3:Dictionary>
            </sap:WorkflowViewStateService.ViewState>
            <SendReply DisplayName="SendReplyToReceive" sap:VirtualizedContainerService.HintSize="255,90">
              <SendReply.Request>
                <Receive x:Name="__ReferenceID2" sap:VirtualizedContainerService.HintSize="277,100" OperationName="Submit" ServiceContractName="OrderService">
                  <Receive.CorrelatesOn>
                    <XPathMessageQuery x:Key="key1">
                      <XPathMessageQuery.Namespaces>
                        <ssx:XPathMessageContextMarkup>
                          <x:String x:Key="xgSc">http://tempuri.org/</x:String>
                        </ssx:XPathMessageContextMarkup>
                      </XPathMessageQuery.Namespaces>sm:body()/xgSc:Submit/xgSc:orderId</XPathMessageQuery>
                  </Receive.CorrelatesOn>
                  <Receive.CorrelationInitializers>
                    <RequestReplyCorrelationInitializer CorrelationHandle="[__handle2]" />
                  </Receive.CorrelationInitializers>
                  <ReceiveParametersContent>
                    <p:OutArgument x:TypeArguments="x:Int32" x:Key="orderId" />
                  </ReceiveParametersContent>
                </Receive>
              </SendReply.Request>
            </SendReply>
            <p:Assign sap:VirtualizedContainerService.HintSize="255,58">
              <p:Assign.To>
                <p:OutArgument x:TypeArguments="x:Boolean">[OrderSubmitted]</p:OutArgument>
              </p:Assign.To>
              <p:Assign.Value>
                <p:InArgument x:TypeArguments="x:Boolean">True</p:InArgument>
              </p:Assign.Value>
            </p:Assign>
          </p:Sequence>
        </p:PickBranch>
      </p:Pick>
    </p:DoWhile>
  </p:Sequence>
</WorkflowService>

 

Enjoy!

 

www.TheProblemSolver.nl

Wiki.WindowsWorkflowFoundation.eu