Table of Contents
The goal of this article is to help developers get familiar with Workflow Foundation 4.0.
It provides a programming model, in-process workflow engine, and a re-hostable designer to implement long-running processes as workflows within .NET applications. MSDN.
This article will provide a step-by-step guide to build and test a simple calculator Web Service in WF 4.0. I will be mostly using built-in WF activities to build the workflow. In addition, I will build a simple custom code activity to go over the custom activities.
The task of the service will be to take three parameters, two for operands and one for operation name, and return the result back to the client after applying the operation. The diagram below explains the complete flow that we are going to implement during this exercise, and our workflow will look like this flow chart at the end.
Building workflow applications will be similar to building this flow chart. Each box in the above diagram will be called activity, and all the activities will be contained in a larger activity called Main Activity. Most of the activities needed to build this application will be provided by Visual Studio 2010, and we will add a new custom activity to log the data into a file to track the application.
- Launch Visual Studio 2010
- Select Project->New
- Select "WorkFlow" under "Installed Templates->Visual C#"
- Select "WCF Workflow Service Application"
- Change the name of the project to "CalculatorWFService"
- Click OK to close this window
This will create a project using a Workflow Service Template, with three built-in activities: Sequense, ReceiveRequest, and SendResponse (see the designer window in the figure below).
The SequenceActivity is a CompositeActivity, meaning the SequenceActivity can contain other activities. The SequenceActivity
class coordinates the running of a set of child activities in an ordered manner, one at a time. The SequenceActivity is completed when the final child activity is finished.
Receive Activity will wait until a client connects to the service and then runs its contained child activities. MSDN.
Client activity that models the synchronous invocation of a service operation.
- Click on the sequence service to Main Sequence (to match the workflow in Fig. 1). This renaming will not have any effect on the application, but it will improve the readability of the workflow.
- Rename the Service1.xamlx file to CalculatorService.xamlx by right clicking on the file.
- By default, the workflow service template configures the service with the "
GetData
" web operation name (think of it as a web method). To rename this method, click on the "ReceiveRequest" activity and change the "Operation Name" property to "Calculate". Also, change the service contract property to "ICalculate".
Select the activity called "Main Sequence" and click on the "Variables" button at the bottom of the designer window.
This action will open up a Variables window (highlighted below).
Remove the "data" variable by selecting the complete row. As soon as the variable "data" is deleted, the designer will show an error icon on the activities which no longer have the "data" variable that they were using. This is a very helpful feature for debugging and tracking design time issues.
For now, let's just ignore these error icons and keep moving on. They will disappear after we are done with the activity configurations. Add variables to hold the three input parameters by clicking on the "Create Variable" text in the variable window. Create two parameters of type int32
(use the drop down control in the "variable type" column to select the variable type) and name them "Operand1
", "Operand2
". Create a third variable of type "string
" and name it "OperationName
". Also, let's add a fourth variable called "Result
" of type string
to hold the result (see the screenshot below) and send it back to the caller application.
These variables are just like adding class level variables which will be accessible to all the class methods. In this case, they will be available to all the activities within the "Main Sequence" activity.
Now we have to configure the Receive Activity to accept the following three parameters. To do this, you will have to select the Receive Activity and change its "Content
" property by clicking the button. This will open up the "Content Definition" window. Click on the parameter radio button to define the parameters. The Message data option can be used to receive custom class objects.
Define three parameters (as shown in the figure above) by clicking on the "Add new parameters" text. "parameter1
" and "parameter2
" will hold two numbers, and "operationName
" will hold the name of the operation to be performed on these numbers.
After adding parameters, we have to assign workflow level variables to the parameters so that all the input data will be available for all the workflow activities. To do this, just select the "Enter a VB expression" text in the cell next to the parameter name and type in the variable that you want to assign to the parameter. In this exercise, I will assign parameter1
to operand1
, parameter2
to operand2
, and operationName
to the OperationName
workflow variable.
Click OK to close the window.
To configure the Send Activity, select the "SendResponse" activity in the designer. Change its "Content
" property to configure what to send back to the caller. Select the button next to 'Contents' in the property box. This will open up a new "Content Definition" window same as what we have seen before during the Receive Activity configuration. We do not have to configure parameters here. Message configuration will do just fine. Just remove "data.ToString()
" with the "Result
" variable that we have declared in the beginning. One more great feature of the designer is that it provides intellisense help throughout the process, and that makes it easier to select and find variables available (see screenshot below).
Click OK to close the window and get back to the designer.
Now we are done with the Web Service input and output configurations. The next step is to perform some operation based on the "operationName
" parameter. For that, we are going to use a flow chart activity. Before we start to build a flow chart, let's build a custom code activity to log some trace information in a file and also add some text to the final result. We will use this activity in the flow chart.
- Right click on the CalculateWFService project and select Add New Item.
- Then, in the Installed Templates section, select "workflow".
- Select "Code Activity".
- Click "Add" to add this activity to the project (we will leave the default name "codeactivity1.cs" as is).
- Every code activity can have input and output arguments just like any C# method having input and output parameters. I find it easier to think of it as a C# class method and the way it deals with the input and output parameters. The only exception is that in code activity, they have to be declared as
InArgument
s and OutArgument
s, and have to be accessed via the current context. In this code activity, we are going to use the default text InArgument
, and will add an OutArgument
"result
". Just type the following in the top section of the class:
public OutArgument<string> result { get; set; }
- Add the following simple execution code in the
Execute
method of the code activity class:
File.AppendAllText(@"C:\WorkflowLog.txt", "Result is:" + text);
context.SetValue(result, "Result is:" + text);
All this code is doing is writing the input of this code activity in a file and returning the input of the activity after appending some text in it. Also, you will have to add the following in the file header:
using System.IO;
In code activities, all the activity execution logic should be written in the Execute
method. Please check the following link for more information on code activities and the Execute
method: http://msdn.microsoft.com/en-us/library/ee264176.aspx.
- Build the project at this point to check for any errors and to add this new code activity in the "Toolbox".
- Select "CalculatorService.xamlx" to go back to the designer.
There are other options to get the result, and this simple task can be accomplished by using a custom code activity or via a simple expression in the Send Activity's configuration. But my goal is to give an overview of as much workflow features as possible in this exercise, and this is why I am going to use a flow chart.
A Flowchart Activity is an activity that contains a collection of activities to be executed. Flowcharts also contain flow control elements such as FlowDecision
and FlowSwitch
that direct execution between the contained activities based on the values of variables.
Different types of elements are used depending on the type of flow control required when the element executes. Types of flowchart elements include:
Models one step of execution in the flowchart.
Branches execution based on a Boolean condition, similar to If.
Branches execution based on an exclusive switch, similar to C# switch
. Each link has an Action
property that defines a ActivityAction that can be used to execute child activities, and one or more Next
properties that define which element or elements to execute when the current element finishes execution. You can fine out more about flowcharts here.
OK, enough about flowcharts; let's get started on building one to calculate the result.
Step 1: Expand the "Flowchart" section in the VS Toolbox, and drag the flowchart activity and drop it between the "ReceiveRequest
" and SendResponse
" activities (see the screenshot below).
Step 2: Double click on the text in the Flowchart activity to start drawing a flowchart. This will take you to the flowchart designer window. Please notice another great feature of the designer: breadcrumb navigation on the top of the designer which can be used to go back to the top level activities.
Step 3: Drag the "FlowSwitch<t>" activity from the toolbox and drop it under the Start activity. Select "String" on the "Select types" window, which will pop up as soon as the activity is dropped on the designer.
- Select "Switch" in the designer window.
- Click on the button next to "Expression" in the property window.
- Type in "OperationName" in the expression editor (Intellisense will help you select the variable), and click OK to close the window.
- Now the switch is configured to evaluate the "
OperationName
" variable and to decide the path that it will have to take based on its value. So, let's define different paths for different values. In this exercise, I am going to only perform three calculations: addition, subtraction, and multiplication, and if operationName
is not "add", "subtract", or "multiply", then I will return a "not implemented" message (take a look at the flow chart in the beginning of the article). Select "CodeActivity1" in the toolbox, and drop it four times in the flowchart designer window. - Draw lines from the "Start" node to the "Switch" node, and then draw four lines from the "Switch" node to each of "CodeActivity1". To draw a line, just hover the mouse pointer over an activity and drag a line to the next activity.
- Select each line except the "default" line, and change "Case" in the property window to "add", "subtract", and "multiply", as shown in the figure below:
If you remember, "Text
" is the input argument for the code activity, and "result
" is the output argument. In the following few steps, we are going to set these input and output arguments for all the code activities that we dropped in the designer.
- Select the "CodeActivity1" which is linked to the "add" case, and type the "(Operand1 + Operand2).toString()" expression in the "
Text
" property. Type "Result" in the "result
" property expression. - Select the "CodeActivity1" which is linked to the "subtract" case, and type the "(Operand1 - Operand2).toString()" expression in the "
Text
" property. Type "Result" in the "result
" property expression. - Select the "CodeActivity1" which is linked to the "multiply" case, and type the "(Operand1 * Operand2).toString()" expression in the "
Text
" property. Type "Result" in the "result
" property expression. - Select the "CodeActivity1" which is linked to the "default" case, and type the "Not implemented" expression in the "
Text
" property. Type "Result" in the "result
" property expression.
The flowchart activity will check the input variable "OperationName
" and will take the appropriate execution path. At the end of each path, we are setting the workflow level variable called "Result
" to some value via "codeActivity1". After the flow chart, the workflow will execute the send activity which will result in the "Result" value sent back to the caller.
So this is it folks, our workflow service is ready.
Now, let's test this using WCFTESTClient.exe. This exe can be found under the "C:\Program Files \Microsoft Visual Studio 10.0\Common7\IDE\WcfTestClient.exe" path. This tool can be used to test any WCF Web Service. Just follow the steps below to test our calculator service:
- Right click on the project and select Properties.
- Click on the "WEB" tab on the left of the properties page.
- Click on the "Start external program" radio button.
- Type the WCFTestClient.exe path in the textbox (C:\Program Files \Microsoft Visual Studio 10.0\Common7\IDE\WcfTestClient.exe).
- Save the application.
- Let's get the Web Service reference path by right clicking on the ".xamlx" file in Visual Studio's Solution Explorer window and selecting the "Browse" option for the menu. We will need this for the test utility.
- Copy the Web Service link from the browser.
- Press F5 to run the application.
- This will launch the WCFTestClient application; see the screenshot below:
- Right click on the "My Service Project" to add the Web Service reference and paste the service path that we copied in Step 7. This will add the Web Service reference in the WCF test client application.
- Click on Calculate in the left window, and then expand it in the right side window to see all the input parameters. Set the input parameter values and click "Invoke" to invoke the Web Service method. The bottom "Response" window will display the result. Take a look at the screenshot below:
Conclusion
Hope this exercise gave you some insight into Windows Workflow Foundation. In my next article, I will try to deploy this in IIS, and will configure it for monitoring using AppFabric. Also, I will try to go over some of the basic and most important workflow features like persistence, workflow execution, and monitoring using AppFabric.