Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

Establishing Correlation Between Multiple RECEIVE in WF4

4.00/5 (4 votes)
22 Jan 2010CPOL7 min read 40.8K   785  
A simple program to understand correlation in WF4

Introduction

My objective is to give an introduction to the inherent Correlation feature available in WF4 through a simple application. You need to have VS 2010 B2 installed to explore the attached code. The correlation that I'd touched on here is between multiple receives of the WF service. In earlier versions, we have to explicitly establish the correlation using GUID.

Steps to Create Correlation Application

The following steps are involved in creating Correlation WF4 application.

  1. Create the Data Entity Library.
  2. Create WF Service.
  3. Create Client Application to Call/Use the WF Service.

Scenario

The scenario I've taken is very simple so that it will be easy to understand the correlation logic. In WF4, you can create a correlation using any data member (which is used to uniquely identify an instance). Let's take a Customer Registration App which knows Customer First Name in the first hand and then updates the Last Name later. So, obviously, we need two(2) receive activities.

Step 1: Create the Data Entity Library

Let us start by creating the data entity library which is shared between the WF service and the Client. This entity library will have 3 private members and 3 public properties to access and assign values.

  1. Start VS 2010 B2.
  2. File -> Open -> New Project -> Select VC# -> Class Library and Name it as Customer.
  3. Rename Class1.cs to Customer.cs and add reference to System.Runtime.Serialization class.
  4. In the code, refer to that class using “using” statement. Add the [DataContract] attribute on top of the Class declaration. Add three private members and Public get, set Properties for First Name, Customer ID and Last Name. Add [DataMember] attribute on top of each of the properties.

Your code should look like...

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization; 
namespace Customer
{
   [DataContract]
    public class Customer
    {
        private string _firstName;
        private string _lastName;
        private Int32 _customerID;

        [DataMember]
        public string FirstName { get { return this._firstName; } 
				set { _firstName = value; } }
        [DataMember]
        public string LastName { get { return this._lastName; } 
				set { _lastName = value; } }
        [DataMember]
        public Int32 CustomerID { get { return this._customerID; } 
				set { _customerID = value; } }
    }
}

Step 2: Create WF Service

  1. Right Click the same solution and add a new Project of type Workflow Console Application. Double Click Workflow1.xaml to go to the design view. Drag and Drop the “Sequence” from “Control Flow” to the center of the design window. Drag and Drop the “ReceiveAndSendReply” from the Messaging toolbar section on to the body of the “Sequence” control. Again drag and drop the same ReceiveAndSendReply from the Messaging toolbar beneath the earlier ReceiveAndSendReply.

    Please refer to the Image for the WF Design (as of now, don’t bother about the updated Operation Name, Text, etc. in the image).

    Image 1

  2. Click the Outer Sequence control. Select “Variables” from the bottom left bar and create the following variables. Before that, refer the Customer (Entity Library) to this Console Application by clicking Add reference from the Solution explorer.
    Variable NameVariable TypeScope
    __handleCorrelation HandleSequence
    CurrCustomerCustomerSequence

    From the dropdown, select System.ServiceModel.Activities.CorrelationHandle as variable type for __handle, likewise, choose Customer.Customer for the CurrCustomer variable. __handle variable is used as handler to route the next call to the already existing instance and CurrCustomer will hold the current state of the Customer object passed to the Service.

  3. Select the “Receive” activity from the first Sequence control inside the main sequence. Do the following in the Properties window for the “Receive” activity.
    C#
    OperationName = CreateCustomer 
    ServiceContractName = CustomerService 
    CanCreateInstance = True (Check the check box) 
    CorrelatesWith = __handle 
    CorrelatesOn = From the Xpath Query Dropdown, select Customer ID 
  4. Click “View Parameters” button inside the “Receive” box to add parameters to this activity from the client app. Select Parameters radio button and enter the following:
    NameTypeAssignTo
    valueCustomerCurrCustomer

    This step assigns the Customer object to the local variable CurrCustomer for further processing within the Workflow service.

  5. Add “Assign” control (from Primitives section of the toolbar) between the Receive and “SendReplyToReceive” controls. This action is to assign any values in the Service. Click the button next to “To” in the properties window after selecting this control from the design panel. You should be able to type CurrCustomer.CustomerID without any errors. If there is any error, a red info image will display towards the end of the box. Click OK and close it. Click the button next to Value from the Properties box and enter New Random().Next(). This will assign a new Customer ID (integer) to the existing Customer object in the service). Click “View Parameters” button of the “SendReplyToReceive” box and add the following:
    NameTypeValue
    resultAdd String "Customer Added. ID for " + CurrCustomer.FirstName is " + CurrCustomer.CustomerID.ToString()

    Note: The Syntax to follow here in XAML is VB syntax. So, we should be learning both C# and VB. This resultAdd will be sent back to the Client app as string.

  6. Drag and Drop WriteLine component from the Primitives section next to SendReplyToReceive. This is to print on the Service Console window to see what is happening in the service.
  7. Click the button next to “Text” property in the Properties window and copy and paste the following:
    C#
    "Customer ID Created for " + CurrCustomer.FirstName + " " + 
    	CurrCustomer.LastName + "=" + CurrCustomer.CustomerID.ToString() 

    With these above steps, one part of the action which is creating Customer ID for the passed in Customer is done. Now, we are going to create one more Receive activity to add Last Name to the already existing Customer Object in the Service.

  8. Select the Second Sequence in the Design window and click Variables in the bottom left bar and add the following variables:
    NameVariable TypeScope
    lNameStringSequence
    custIDInt32Sequence
  9. Variable lName is to hold the passed-in Last name value from the client app and so is the custID to hold the Customer ID. Click the “View Parameters” button from the receive Component and add the following variables. Choose Parameters option button.

    NameTypeAssignTo
    valueStringlName
    IDInt32custID
  10. Select Receive activity and add the following values to the corresponding properties:
    • OperationName = AddLastName
    • ServiceContractName = CustomerService
    • CorrelatesWith = __handle (this is the one which correlates the first receive and second receive activity)
    • CorrelatesOn = Choose “ID : Int32” from the Xpath queries dropdown. This ID is the parameter which we are going to pass from the Client App as defined in the previous step.

    Here we should not check the CanCreateInstance property as the instance is already created by the first Receive and from this time around we are going to update the already existing Customer object in the Service app.

  11. Insert Assign component from the Primitives section between Receive and SendReplyToReceive sections in the design area. In the To text box, type the following CurrCustomer.LastName. In the value text box, type lName (local variable name)
  12. Click “View Parameters” button in the SendReplyToReceive box and add the following. Choose parameters option button.
    NameTypeValue
    resultAddString"last Name " + CurrCustomer.LastName + " added to Customer ID " + CurrCustomer.CustomerID.ToString()

    This is the value going to be returned to the Client App.

  13. Finally, drag and Drop the WriteLine Component and type the following in the Text property to see what is happening in the Service.
    C#
    "Customer Name :" + CurrCustomer.FirstName + " " + 
    	CurrCustomer.LastName + " ID : " + CurrCustomer.CustomerID.ToString() 

    We are done with creating the WF4 Service in the XAML.

  14. Open the Program.cs of the WF Service App and type the following.
  15. Refer System.ServiceModel.Activities and System.ServiceModel.Description assemblies.
  16. Inside the main method, copy and paste the following:
    C#
    string baseAddress="http://localhost:8081/CustomerService";
    using (WorkflowServiceHost shost = 
    	new WorkflowServiceHost(new Activity1(), new Uri(baseAddress))) 
    { 
        shost.Description.Behaviors.Add(new ServiceMetadataBehavior() 
    	{HttpGetEnabled = true }); 
        shost.Open(); 
        Console.WriteLine("CustomerService is listening @ " + baseAddress); 
        Console.ReadLine(); 
    } 

Build the solution and make sure that there is no type error or any other build errors. Go to bin/debug of the WF Service Console App and Run the Console App.

Step 3: Create Client Application to call the WF Service

  1. Right Click the solution and add VC# Console Application and name it as ClientApp. Refer the Customer library to the project. Right Click “Service Reference” of the ClientApp and click Add Service reference. In the Address bar type http://localhost:8081/CustomerService and click Go. Form the Services Box, choose the Service and click OK. Now, you have added a reference to the Running Service in the localhost.

    Note: Every time you make a change to Service, you need to update the Client App.

  2. Open the Program.cs of the ClientApp and copy and paste the following within Main method.
    C#
    ServiceReference1.CustomerServiceClient csClient = new CustomerServiceClient(); 
    Customer.Customer cust = new Customer.Customer(); 
    string fName; 
    Console.WriteLine("Enter First Name : "); 
    fName =Console.ReadLine(); 
    cust.FirstName = fName; 
    string response = csClient.CreateCustomer(cust); 
    Console.WriteLine(response); 
    Console.ReadLine(); 
    try 
    { 
        Console.WriteLine("Enter last Name : "); 
        cust.LastName = Console.ReadLine(); 
        string response1 = csClient.AddLastName
    			(cust.LastName.ToString(), cust.CustomerID); 
        Console.WriteLine(response1); 
        Console.ReadLine(); 
    } 
    catch (Exception ex) 
    { 
        //Publish the error
    }

That’s it. You are done with the coding. Now, set the ClientApp as the staring project and click Run button. Alternatively, you can go and execute the EXE from bin/debug folder of the ClientApp.

History

  • 22nd January, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)