Receive data in your host application or calling workflow Using the service class you created, hook the “data available” event and call the services “read” method.Invoke secondary workfl
Trang 110 This activates the Browse And Select A NET Type dialog box Select Workflow2 in the left
pane, which displays the Workflow2 type in the right pane Select the Workflow1 type (Workflow2.Workflow1 is the fully qualified name) in the right pane and click OK.
11 Visual Studio then examines the Workflow2 workflow and displays its graphical
representation inside the InvokeWorkflow activity in the visual workflow designer.
12 The workflow implementations are now complete, so we can add them as references to
the main WorkflowInvoker application From Solution Explorer, right-click the flowInvoker project and select Add Reference When the Add Reference dialog box appears, click the Projects tab Select both Workflow1 and Workflow 2 from the list and click OK
Trang 2Work-15 We’ll now add a small amount of code to the host application simply to tell us when
each workflow completes Insert the following code in the event handler for
The first workflow to complete sets the AutoResetEvent we’re using to force the application to
wait for workflow completion We could add code to force the application to wait for both workflows, but for demonstration purposes this should suffice If you compile and execute the WorkflowInvoker application, you’ll see console output similar to what you see in Figure 8-4 If the output messages appear in a slightly different order, don’t be alarmed This is the nature of multithreaded programming
Figure 8-4 The WorkflowInvoker application console output
If you want to continue to the next chapter, keep Visual Studio 2005 running and turn to Chapter 9, “Logic Flow Activities.” It’s one thing to crunch numbers, but we also need tools to make decisions, and that’s the next topic
If you want to stop, exit Visual Studio 2005 now, save your spot in the book, and watch your favorite movie on DVD Be sure to fast-forward through any boring parts
Trang 3Chapter 8 Quick Reference
Design workflow/host data transfers Create an interface with methods designed to pass
the data back and forth Be sure to add the
ExternalDataExchange attribute, as well as the
correla-tion attributes, as we did in the sample applicacorrela-tion Create the “data available” event arguments Derive an event argument class from
ExternalDataEventArgs, and anoint it with
information you need to pass back and forth
Create the external data service This is a somewhat complex task in that you must write
a lot of code yourself to manage the data (which can come from any number of workflow instances) But
in general, you create a class (the connector) that
manages the data (and is plugged into the workflow runtime because it manages workflow state) and
another class (the service) that the host application (or
invoking workflow) uses to hook the “data available” event and read (or write) the data
Create the communications-based activities With your interface in hand, run wca.exe The wca.exe
tool creates a pair of activities for you: one to send data to the external (workflow) process and one to receive data In this chapter, we looked only at sending data, but in Chapter 17 we’ll revisit this topic and build
a bidirectional interface
Receive data in your host application (or
calling workflow) Using the service class you created, hook the “data available” event and call the services “read” method.Invoke secondary workflows Add an instance of InvokeWorkflow to your workflow
process, and provide the data type of the workflow to
be invoked Note you have to add a reference to the secondary workflow to accomplish this
Trang 4workflows We’ve seen how to execute code, both within and outside our workflow instances, and we know how to handle exceptions, suspend processing, and even terminate our work-flow if things get out of hand But certainly a major component for any computational system
is the ability to make decisions based on runtime conditions In this chapter, we begin to address workflow activities that require us to tackle if/else scenarios as well as basic looping
Conditions and Condition Processing
By now, it probably won’t surprise you to find that Windows Workflow Foundation (WF) provides activities for logical process control flow based on runtime conditions After all, if
WF provides activities to both raise and catch exceptions, why not have activities to ask tions regarding executing workflow conditions and make decisions based on those findings?
ques-The activities we’ll examine in this chapter include the IfElse activity, the While activity, and the Replicator activity The IfElse activity is designed to test a condition and execute a
different workflow path depending on the result of the test (We actually used this activity in Chapter 1, “Introducing Microsoft Windows Workflow Foundation,” when we asked whether
or not a given postal code was valid when tested against a regular expression.) The While activity, perhaps not too surprisingly, is used to perform a while loop A for loop, however, is accomplished using something known as the Replicator activity Let’s start by looking at this
chapter’s sample application
Note The conditional processing you’ll do in this chapter is based on the CodeCondition,
which means you’ll write C# code to process the conditional expression In Chapter 12,
“Policy And Rules,” you’ll use the RuleCondition which uses WF rules-based processing for
conditional expression evaluation Both are equally valid I simply chose to include
RuleCondition, in the same chapter I discuss rules-based processing in general.
Trang 5The Questioner Application
This chapter’s sample application is a Windows Forms application that asks you three questions, the text for which you can modify (The question text is stored in the application’s settings property bag.) You can also indicate whether the questions are dependent or inde-pendent You’ll pass the questions and dependency status into the workflow as it begins execution
Dependent questions will continue to be asked only if the previous questions were answered
in the affirmative For example, if you’re asked, “Have you seen the document in question?” and you have not, it makes little sense to ask, “Do you approve this document?” If the ques-tions are dependent, the first negative response returns negative for the given response as well
as for all remaining question responses
Independent questions will always be asked regardless of preceding responses The question,
“Do you like ice cream?” is unrelated to “Is it raining outside at this time?” Whether you do or
do not like ice cream, the answer to that question is independent of the weather outside pendent questions continue to be asked whether you provide a negative response to an earlier question or not
Inde-The user interface appears as you see in Figure 9-1 If you modify the text for any of the three questions, the new question text will automatically be stored in your application settings property bag (The same is true of the question type.) The questions are intended to generate yes/no responses so that the workflow can pass the responses back to the host application as
an array of Boolean values
Figure 9-1 The Questioner primary user interface
When you click the Execute button, the questions appear in order as message boxes with Yes and No buttons Once the workflow has processed all the questions, it returns a Boolean array
to the host application The host application will examine the array for user-interface display purposes
While the workflow is executing, the responses appear as blue balls (as you see in Figure 9-1) When the workflow task has completed, affirmative responses are shown as green balls and negative responses are shown as red balls If all responses were affirmative, the “final answer” image appears as a green ball However, if any of the three questions resulted in a negative response, the final answer appears as an “8 ball.” You can see the application in action in Figure 9-2
Trang 6of action to take (affirm or negate a response, and continue based on the dependency setting
if a given response was negative) The second iteration will use the While activity to ask tions while questions remain to be asked And the final iteration will use the Replicator activity
ques-to simulate a for loop ques-to ask the questions For each of these application iterations, we’ll use
the technique shown in the previous chapter to return the responses to the host application
With that in mind, let’s look at using the IfElse activity.
Using the IfElse Activity
The IfElse activity is designed to simulate an if-then-else conditional expression, and in fact
you’ve used this activity in previous chapters (notably in Chapter 1, where the workflow decided whether a given postal code was valid)
The IfElse activity requires you to provide a conditional expression, which is actually
implemented as an event handler The event arguments, of type ConditionalEventArgs, have a Boolean Result property you set to indicate the results of the conditional expression you build
into the event handler
Depending on the Result value, the IfElse activity directs workflow execution to one of two branches Visually, in the Microsoft Visual Studio workflow visual designer, true executes the path shown on the left and false executes the path to the right Both branches are containers
for other activities, allowing you to insert whatever workflow activities are required to process the information or application flow given the Boolean conditional value Let’s drag and drop
a few of these into our sample application and give them a try
Note As you’ll probably agree after working through this section, the IfElse activity
probably isn’t the best activity you could use to model this workflow You’ll find activities better suited for this particular workflow later in the chapter (In fact, this was intentional
on my part.)
Trang 7Creating the QuestionFlow workflow using the IfElse Activity
1 Open Visual Studio, and open the Questioner application’s solution from the book
samples You’ll find the solution in \Workflow\Chapter 9\IfElse Questioner Simply click File, then Open, and then finally Project/Solution Using the resulting Open Project dialog box, browse your computer’s file system until you find Questioner.sln and click Open
2 Scanning Visual Studio Solution Explorer, you should see a solution layout similar to the
one from the previous chapter The main application files are located in the Questioner project, while the host communication service files are located in the QuestionService project So that you can concentrate on the workflow aspects of this application, I have
already created the service interface, IQuestionService, and executed the wca.exe tool to create the necessary communication activity, SendReponseDataToHost To begin, locate
the QuestionFlow project and open the Workflow1.cs file for editing in the Visual Studio workflow visual designer Select Workflow1.cs in Solution Explorer, and then click the View Designer toolbar button as you have in previous chapters
3 When Workflow1 is ready for editing in the workflow visual designer, drag an IfElse
activ-ity from the Toolbox to the designer’s surface and drop it This inserts an IfElse activactiv-ity
item into your workflow
4 The exclamation mark (!) you see, outlined by the red circle, tells you that more
information is required to compile your workflow In fact, what’s missing is the
conditional expression itself! Select the left branch of ifElseActivity1 to bring the activity’s properties into the Visual Studio Properties pane Select Condition to activate the drop-
down list, and from the list select Code Condition
Trang 8Note You actually have two choices for conditional expressions: code and based We’ll use the code-based conditional expression here, saving the rules-based technique for Chapter 12, “Policy Activities.”
rules-5 Expand the resulting Condition property, type in the value AskQuestion1, and press
Enter Visual Studio inserts the AskQuestion1 event handler for you and switches to code
view For now, return to the workflow visual designer so that you can drag more activities into your workflow
6 With the Visual Studio workflow visual designer active, drag a CodeActivity onto the
designer’s surface and drop it into the right-hand branch of IfElseActivity1.
Trang 97 Assign the code activity’s ExecuteCode property the value of NegateQ1 When Visual
Studio inserts the NegateQ1 event handler and switches to the code editor, again return
to the workflow visual designer to drag one more activity onto the designer’s surface
8 Repeat steps 6 and 7, but this time drop the code activity into the left branch of
IfElseActivity1.
Assign its ExecuteCode property the value AffirmQ1 However, when Visual Studio
inserts the AffirmQ1 event handler, do not switch back to the workflow visual designer
Instead, it’s time to add some code
Trang 109 We now need to add some properties to the workflow class that we can assign as
parameters when we start our workflow processing Following the Workflow1
construc-tor, add the following lines of code to contain the three questions the workflow will ask:private string[] _questions = null;
public string[] Questions
{
get { return _questions; }
set { _questions = value; }
}
10 We also need to add the Dependent property, which is used to tell whether the questions
are or are not independent of one other After the code you inserted in the preceding step, add the following:
private bool _dependent = true;
public bool Dependent
{
get { return _dependent; }
set { _dependent = value; }
}
11 The question responses, as Boolean values, need to be stored somewhere until returned
to the host application Therefore, following the Dependent property you just inserted,
add this field:
private bool[] _response = null;
12 The _response field is uninitialized, so locate the Workflow1 constructor and add this
code after the InitializeComponent method invocation:
// Initialize return vector
_response = new bool[3];
_response[0] = false;
_response[1] = false;
_response[2] = false;
Trang 1113 Now scan down the code file until you find the AskQuestion1 event handler Visual Studio
added for you To this event handler, add the following lines of code:
// Ask the question!
DialogResult result = MessageBox.Show(Questions[0], "Questioner:",
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
e.Result = (result == DialogResult.Yes);
14 To the NegateQ1 event handler, add this code:
16 You have just added the workflow components designed to ask the first question
However, two more questions remain For the second question, repeat steps 3 through
8 to add the IfElse activity to the workflow, substituting references to question 1 with references to question 2 Doing this inserts the event handlers AskQuestion2, NegateQ2, and AffirmQ2 The workflow visual designer will appear as follows:
Trang 1218 To the NegateQ2 event handler, add this code:
20 Repeat steps 3 through 8 once again to add the third question, substituting references
to the first question with references to the third question Doing this creates the
AskQuestion3, NegateQ3, and AffirmQ3 event handlers At this point, the workflow
visual designer should appear like so:
Trang 1321 Locate the AskQuestion3 event handler and insert these lines of code:
if (_response[1] == false && Dependent)
// Ask the question!
DialogResult result = MessageBox.Show(Questions[2], "Questioner:",
24 Now return to the workflow visual designer If you move the mouse pointer to the
Toolbox and allow the Toolbox to open, you should find a custom activity called
SendResponseDataToHost (Note that if the SendResponseDataToHost activity isn’t in the
Toolbox, compile the project and then look again.)
25 Drag an instance of SendResponseDataToHost onto the workflow visual designer, and
drop it after the third question’s IfElse activity, ifElseActivity3.
Trang 1426 Because the data to be returned is simply an array of value types (Boolean values), the
process is slightly different than in the previous chapter Instead of adding a dependency
property to contain the Boolean array, the SendResponseDataToHost activity contains the
data as a field The user interface to create the field differs from the user interface you
saw in Chapter 7 (in step 8 of the “Creating a workflow using the Throw activity” procedure) Select the responses property in the Visual Studio Properties pane, and
click the browse (…) button
This activates the Boolean Collection Editor dialog box
Trang 1527 Click the Add button three times, leaving the default values as False, and then click OK
Visual Studio adds a three-element Boolean array to your code for you in the
because it made more sense (from an illustrative standpoint) to show how to add and
work with IfElse activity objects before dealing with the host communication activity
28 We need to tie the response array we’re using for our question responses to the value the
SendResponseDataToHost activity will use (the property we created in steps 26 and 27)
Therefore, drag a CodeActivity onto the workflow visual designer and drop it between the third IfElse activity, ifElseActivity3, and the SendResponseDataToHost activity,
sendResponseDataToHost1.
29 Enter the code activity’s ExecuteCode property as CopyResponse.
30 When Visual Studio inserts the CopyResponse event handler and activates the code
editor, insert this code:
// Assign outgoing data
sendResponseDataToHost1.responses = _response;
31 Compile the entire solution by pressing F6, and correct any compilation errors.
The host application file has already been created, and the appropriate code has been inserted
to execute the workflow as created here Simply press F5 to execute the application Does
changing the question Dependency property have any effect when asking questions and
providing negative responses?
Trang 16it uses ConditionalEventArgs to return your decision (again using the Result property) However, unlike using the IfElse activity, when you are using the While activity, setting Result to
true causes the loop to continue Setting Result to false breaks the loop Let’s see how switching
the conditional processing from if-then-else to a while loop simplifies our workflow.
Creating the QuestionFlow workflow using the While Activity
1 Open Visual Studio, and again open the Questioner application’s solution from the book
examples In this case, you’ll find the solution in \Workflow\Chapter 9\While tioner Click File, then Open, and then finally Project/Solution Using the Open Project dialog box, again browse your computer’s file system until you find Questioner.sln and then click Open
Ques-2 As with the preceding section, the application is essentially complete, including the
creation of the SendResponseDataToHost activity What remains to be completed is the
workflow processing itself Look at the Solution Explorer pane and find the
Workflow1.cs file in the QuestionFlow project Select it in the tree control, and click the View Designer toolbar button to load it into the Visual Studio workflow visual designer
3 When Workflow1 is ready for editing in the workflow visual designer, drag an instance of
the While activity from the Toolbox to the designer’s surface and drop it, inserting a
While activity item into your workflow.
Trang 174 In a manner similar to the IfElse activity, select the Condition property for the
whileActivity1 activity to activate its drop-down list From the drop-down list, select Code
Condition
5 Expand the Condition property, type TestComplete, and press Enter to add the
TestComplete event handler to your workflow code After Visual Studio inserts the
event handler and switches the user interface to the code editor, return to the workflow visual designer
6 With the workflow visual designer active, drag an instance of CodeActivity and drop it
in the center of whileActivity1 Assign the value AskQuestion to the ExecuteCode
property, and return to the workflow visual editor when the AskQuestion event handler
has been added