
Pro CSharp 2008 And The .NET 3.5 Platform [eng]
.pdf


934 CHAPTER 26 ■ INTRODUCING WINDOWS WORKFLOW FOUNDATION
Invoking Web Services Within Workflows
WF provides several activities that allow you to interact with XML web services during the lifetime of your workflow-enabled application. When you wish to simply call an existing web service, you can make use of the InvokeWebService activity.
■Note Given that WCF is the preferred API to build services, this edition of the text does not cover the construction of XML web services in any great detail (Chapter 25 broached the topic in passing); therefore the web service we will be calling here is intentionally simple.
Creating the MathWebService
The first task is to build an XML web service that can be utilized by a workflow-enabled application. To do so, create a brand-new XML web service project by accessing the File New Web Site menu option. Select the ASP.NET Web Service icon and be sure to select the HTTP location option in order to create this web service within a new IIS virtual directory mapped to http://localhost/ MathWebService (see Figure 26-11).
Figure 26-11. Adding an XML web service project to the WF application
This XML web service will allow external callers to perform basic mathematical operations on two integers using the following [WebMethod]-adorned public members:
[WebService(Namespace = "http://intertech.com/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class MathService : System.Web.Services.WebService
{
[WebMethod]


936 CHAPTER 26 ■ INTRODUCING WINDOWS WORKFLOW FOUNDATION
Building the WF Web Service Consumer
Now create a new Sequential Workflow Console Application project named WFMathClient and rename your initial C# file to MathWF.cs. This application will ask the user for data to process and which operation they wish to perform (addition, subtraction, etc.). To begin, open your code file and define a new enum type named MathOperation:
public enum MathOperation
{
Add, Subtract, Multiply, Divide
}
Next, define four automatic properties in your class, two of which represent the numerical data to process, one of which represents the result of the operation, and one of which represents the mathematical operation itself (note the default constructor of MathWF sets the value of the Operation property to MathOperation.Add):
public sealed partial class MathWF : SequentialWorkflowActivity
{
// Properties.
public int FirstNumber { get; set; } public int SecondNumber { get; set; } public int Result { get; set; }
public MathOperation Operation { get; set; }
public MathWF()
{
InitializeComponent();
// Set default Operation to addition.
Operation = MathOperation.Add;
}
...
}
Now, using the WF designer, add a new Code activity named GetNumericalInput that is mapped to a method named GetNumbInput(), by setting the ExecuteCode value via the Properties window. Within this method, prompt the user to enter two numerical values that are assigned to your FirstNumber and SecondNumber properties:
public sealed partial class MathWF : SequentialWorkflowActivity
{
...
private void GetNumbInput(object sender, EventArgs e)
{
//For simplicity, we are not bothering to verify that
//the input values are indeed numerical.
Console.Write("Enter first number: "); FirstNumber = int.Parse(Console.ReadLine());
Console.Write("Enter second number: "); SecondNumber = int.Parse(Console.ReadLine());
}
}
Add a second Code activity named GetMathOpInput mapped to a method named GetOpInput() in order to ask the user how he or she wishes to process the numerical data. To do so,

CHAPTER 26 ■ INTRODUCING WINDOWS WORKFLOW FOUNDATION |
937 |
we will assume the user will specify the letters A, S, M, or D, and based on this character value, set the MathOperation property to the correct enumeration value. Here is one possible implementation:
private void GetOpInput(object sender, EventArgs e)
{
Console.WriteLine("Do you wish to A[dd], S[ubtract],"); Console.Write("Do you wish to M[ultiply] or D[ivide]: "); string option = Console.ReadLine();
switch (option.ToUpper())
{
case "A":
Operation = MathOperation.Add; break;
case "S":
Operation = MathOperation.Subtract; break;
case "M":
Operation = MathOperation.Multiply; break;
case "D":
Operation = MathOperation.Divide; break;
default:
numericalOp = MathOperation.Add; break;
}
}
At this point we have the necessary data. Now let’s check out how to pass it to our XML web service for processing.
Configuring the IfElse Activity
Given that fact that our numerical data can be processed in four unique manners, we will use an IfElse activity to determine which web method of the service to invoke. When you drag an IfElse activity onto your designer, you will automatically be given two branches. To add additional branches to an IfElse activity, right-click the IfElse activity icon and select the Add Branch menu option. Figure 26-13 shows the current WF designer (note that each branch and the entire IfElse activity have been given proper names).
Each branch of an IfElse activity can contain any number of internal activities that represent what should take place if the decision logic results in moving the flow of the application down a given path. Before we add these subactivities, however, we first need to add the logic that allows the WF engine to determine which branch to take by setting the Condition value to each IfElseBranch activity.
Recall that the Condition event can be configured to establish a code condition or a declarative rule condition. The first example project in this chapter already illustrated how to create a code condition, so in this example we will opt for rule conditions. Starting with the AddBranch, set the Condition value to Declarative Rule Condition using the Visual Studio Properties window. Next, click the ellipsis button for the ConditionName subnode, and click the New button from the resulting dialog box. Here, you are able to author a code expression that will determine the truth or falsity of the current branch. For this first branch, the expression is as follows:
this.Operation == MathOperation.Add

938 CHAPTER 26 ■ INTRODUCING WINDOWS WORKFLOW FOUNDATION
Figure 26-13. A multibranching IfElse activity
You’ll notice that this dialog box supports IntelliSense, which is always a welcome addition (see Figure 26-14).
Figure 26-14. Defining a declarative rule condition
Once you have set each rule, you will now notice that a new file with a *.rules extension has been added to your project (see Figure 26-15).


940 CHAPTER 26 ■ INTRODUCING WINDOWS WORKFLOW FOUNDATION
When you do so, the IDE will generate a proxy to your web service and use it as the value to the InvokeWebService’s ProxyClass property. At this point, you can use the Properties window to specify the web method to invoke via the MethodName property (which is the Add method for this branch), and map the two input parameters to your FirstNumber and SecondNumber properties and the return value to the Result property. Figure 26-17 shows the full configuration of the first InvokeWebService activity.
Figure 26-17. A fully configured InvokeWebService activity
You can now repeat this process for the remaining three IfElse branches, specifying the remaining web methods. Do be aware that even though the Add Web Reference dialog box will appear for each InvokeWebService activity, the IDE is smart enough to reuse the existing proxy, as each activity is communicating with the same endpoint.
Last but not least, we will add one final Code activity after the IfElse logic that will display the result of the user-selected operation. Name this activity DisplayResult, and set the ExecuteCode value to a method named ShowResult(), which is implemented as so:
private void ShowResult(object sender, EventArgs e)
{
Console.WriteLine("{0} {1} {2} = {3}",
FirstNumber, Operation.ToString().ToUpper(), SecondNumber, Result);
}
For simplicity, we are using the textual value of the Operation property to represent the selected mathematical operator, rather than adding additional code to map MathOperation.Add to a + sign

CHAPTER 26 ■ INTRODUCING WINDOWS WORKFLOW FOUNDATION |
941 |
and MathOperation.Subtract to a - sign, and so on. In any case, Figure 26-18 shows the final design of our workflow; Figure 26-19 shows one possible output.
Figure 26-18. The completed web service–centric workflow
Figure 26-19. Communicating with XML web services from a WF application
Communicating with WCF Services Using SendActivity
To complete this example, let’s examine how a workflow-enabled application can communicate with WCF services. The .NET 3.5–centric SendActivity and ReceiveActivity types allow you to build workflow-enabled applications that communicate with WCF services. As the name implies, the SendActivity type can be used to make calls on WCF service operations, while ReceiveActivity provides a way for the WCF service to make calls back on the WF (in the case of a duplex calling contract).