Ken Getz
MCW Technologies LLC
Published: November, 2008
Articles in this series
Download the code for
this article
Introduction
Windows Workflow Foundation (WF), originally introduced as
part of the .NET Framework 3.0 with extensions for Visual Studio 2005’s
designers, has continued to be enhanced for the .NET Framework 3.5 and Visual
Studio 2008. WF makes it possible, and for many workflow scenarios, even easy
to create robust, manageable workflow-based applications. WF is actually many
things: It’s a programming model, and runtime engine, and a set of tools that
help you create workflow-enabled applications hosted by Windows. (For more
information on WF, drop by the portal site).
In this series of tutorials, you’ll work through several
different examples, showing off various important features of WF, and the
corresponding tools and techniques using Visual Studio 2008. Because workflows
generally deal with specific business-oriented processes, and these tutorials
can’t begin to emulate your specific processes, you’ll find that the specific
examples shown here tend to focus on either scenarios that you can control in
order to demonstrate the specific workflow features (such as working with files
in the file system), or they focus on business processes with “holes” left for
your imagination to insert real-world behaviors.
This first tutorial introduces the basics of creating
Workflow applications, using a console application as the workflow’s host.
Along the way, you’ll investigate the various workflow-focused templates that
Visual Studio 2008 provides, and you’ll learn what happens when you create and
run a workflow application. You’ll try out a few of the many different workflow
activities, as well. (These tutorials assume that you have Visual Studio 2008 installed,
along with the .NET Framework 3.5. You can choose to work in either Visual
Basic or C#--the steps listed here call out specific differences between the
languages, when necessary.
There’s a lot to cover in this first tutorial, so fire up
Visual Studio 2008, and get started!
Investigate the Workflow Templates
To get started, in Visual Studio 2008 select File | New |
Project to display the New Project dialog box. In the list of project types,
select Workflow, displaying the list of templates shown in Figure 1.
.jpg)
Figure 1. Visual
Studio 2008 provides these workflow templates.
In general, WF allows you to create two different types of
workflows: sequential, and state machine. Sequential workflows provide a
structured series of steps in which one activity leads to another, and steps
generally occur immediately one after another. A step might wait for some event
(an email to arrive, for example), but sequential workflows are often appropriate for tasks that operate
without human intervention. State machine workflows provide a set of states;
transitions between the states define the behavior. In general, state machine
workflows react to events which move the workflow’s current activity from one
state to another. Each workflow that you design is simply a class that inherits
from one or the other of the
System.Workflow.Activities.SequentialWorkflowActivity or
System.Workflow.Activities.StateMachineWorkflowActivity classes, and most of
the Visual Studio 2008 workflow project templates create a class that inherits
from one or the other of these base classes for you. (In addition, each of
these templates includes assembly references to the various assemblies required
in order to design and run workflows.) If you want to create a sequential
workflow, you can select any of the following templates:
- Sequential Workflow Console Application, which
includes a Console application host application that helps run your workflow.
You’ll investigate this specific template in this tutorial.
- Sequential Workflow Library, which creates a
.NET library containing only a sequential workflow class. This project template
does not include a host application, so you will need to supply your own in
order to execute a workflow.
- Sharepoint 2007 Sequential Workflow, which
creates a sequential workflow suitable for use with SharePoint 2007. (For more
information on SharePoint 2007 and workflows, visit this site.)
If you want to create a state machine workflow (the topic of
another tutorial in this series), you can select any of the following templates,
which correspond to the similarly named templates previously listed:
- SharePoint 2007 State Machine Workflow
- State Machine Workflow Console Application
- State Machine Workflow Library
In addition, you can select the Empty Workflow Project
template to create an empty project, with just the necessary references set; or
you can select the Workflow Activity Library template to create a library in
which you could create custom workflow activities.
Create a Workflow Project
For this demonstration, select the Sequential Workflow
Console Application template, name your application WorkflowDemo1, and select
an appropriate folder for the project. Click OK to create the project. (Note
that every workflow must be hosted by some application—something has to create an
instance of the workflow runtime, which, in turn, creates an instance of the
workflow you want to execute. In this example, you’ll create a Console
application that hosts the workflow.)
At this point, the workflow project contains a single
workflow class, named Workflow1. This blank template should be opened for you
(if not, double-click the corresponding code file in the Solution Explorer
window to open it), and the workflow designer is ready for you to add your own
activities (see Figure 2).
.jpg)
Figure 2. The workflow designer is ready for you to add
activities.
In the Solution Explorer window, right-click the Workflow1
file, and select View Code from the context menu. You’ll find code like the
following, clearly pointing out that the workflow that you’re designing is
really just a class that inherits from the SequentialWorkflowActivity class:
Public class Workflow1
Inherits SequentialWorkflowActivity
End Class
public sealed partial class Workflow1: SequentialWorkflowActivity
{
public Workflow1()
{
InitializeComponent();
}
}
Just as a Windows Form that you design within Visual Studio
becomes an instance of a class that inherits from the System.Windows.Forms.Form
class when you run the application, the workflow that you design within Visual
Studio becomes an instance of a class that inherits from either the
SequentialWorkflowActivity or StateMachineWorkflowActivity class when you run
the application. Later, you’ll add code to this partial class in order to add
behavior to your workflow. (Actually, there’s more of a similarity than just
that—in Visual Studio, when you load a file that contains a class that inherits
from the Form class, Visual Studio displays the form using the Windows Forms
designer. The same thing happens with a workflow class—when you ask Visual
Studio to load a file that contains a class that inherits from one of the two
base activity classes, it displays the class using the appropriate workflow
designer.)
Select View | Designer to return to design view.
Look in the Toolbox window (if it’s not visible, select View
| Toolbox to display it). You’ll see two tabs that deal with Workflow: the tab
labeled Windows Workflow v3.0 contains most of the built-in workflow activities
you’ll use, and the tab labeled Windows Workflow v3.5 contains the new workflow
activities added in the .NET Framework 3.5 (this tab contains only two
activities dealing with WCF and workflow, and you won’t need these items for
these tutorials). For now, select the Windows Workflow 3.0 tab, and expand it
(see Figure 3).
.jpg)
Figure 3. The Windows
Workflow v3.0 tab in the Toolbox window contains most of the built-in workflow
activities.
Some of the activities you see in the Toolbox window have
obvious behavior—the Code activity allows you to execute code, the IfElse
activity allows you to make choices, and the While activity executes an
activity while some condition remains true. Other activities, such as the
SynchronizationScope activity, require a bit more study to determine their
purpose. In this tutorial, you’ll work with the simple Code and IfElse activities—later
tutorials will walk you through using some of the more complex activities, such
as the Replicator, While, Listen, and HandleExternalEvent activities.
Add Activities to the Workflow
To get started, from the toolbox, drag a Code activity onto
the design surface, so that the designer looks like Figure 4 just before you
drop the activity. Once you drop the activity, the designer looks like Figure
5. (Note that as you drag activities onto the designer, you see one or more
green “dots” indicating where, on the workflow, you can drop your activity.)
.jpg)
Figure 4. Before
dropping the activity, you see an icon representing where it will finally
appear within the workflow.
.jpg)
Figure 5. After
dropping the activity, it appears within the workflow design.
At this point, the Code activity indicates an error—you
haven’t yet told it what to do when the workflow attempts to execute it! You’ll
add the code soon. (Although this tutorial doesn’t walk you through the steps,
you should get in the habit of providing meaningful names for your workflow
activities—otherwise, it gets difficult to manage all the activities in your
workflow. Setting the Name property for each activity is a good habit to get
into, but it’s not necessary for this simple workflow.)
At runtime, the sequential workflow starts at the green
arrow, and executes activities, one at a time, in turn, until it reaches the
red circle at the conclusion of the workflow. In your sample workflow, you have
included only a single Code activity. Executing the workflow will cause it to
run any code that you have placed in the activity’s ExecuteCode event handler.
To create the code for your activity, double-click
CodeActivity1. This creates an associated procedure, ready for you to edit in
the code editor. Modify the procedure, adding the following code:
Console.WriteLine("Hello, World!")
Console.WriteLine("Hello, World!");
Select View | Designer, and verify that the error indicator
disappears, because you have provided code for the Code activity to run. Select
the Code activity, and examine the Properties window (see Figure 6). You’ll see
that by adding the event handler, you’ve set the activity’s ExecuteCode
property, so that the activity “knows” what to do when it becomes the active
activity within the workflow.
.jpg)
Figure 6. Adding code
for the Code activity sets the activity’s ExecuteCode property.
Just to verify that you’ve created a working workflow, save
and press Ctrl+F5 to run your project. (If you use any other means to run the
project, the console window will disappear immediately, once the message
appears on the screen.) After a few seconds, the console window displays your
message awaits a key press.
So far, you’ve created the world’s simplest working
workflow, and it really only proved that workflow works at all—clearly, you
would never use WF for a simple application like this. Next, you’ll investigate
how WF loads and runs your workflow design.
Debugging a Workflow
Although this simple application certainly doesn’t require
any debugging capabilities, you’ll often need to step through your workflows.
As you might expect, you can easily place a breakpoint in the ExecuteCode
handler for a Code activity, and step through the code. But what if you want to
debug at a higher level, stepping through activities as they execute? You can,
and Visual Studio makes the process feel much like debugging at the code level.
In the workflow designer, right-click CodeActivity1. From
the context menu, select BreakPoint | Insert Breakpoint. At this point, the
designer places a red dot on the activity, indicating that the workflow will
drop into Debug mode when it begins to execute the activity (see Figure 7).
.jpg)
Figure 7. Set a
breakpoint on an activity.
Press F5 to start running the application. When the workflow
reaches codeActivity1, it pauses execution and highlights the activity in
yellow, as shown in Figure 8.
.jpg)
Figure 8. At runtime,
Visual Studio stops at the activity’s breakpoint.
Select Debug | Step Over (or the corresponding keystroke),
and Visual Studio steps to the next activity, executing the previous Code
activity’s ExecuteCode procedure. Select Debug | Step Into, and Visual Studio
steps into the second Code activity’s ExecuteCode procedure, as you might
expect. Visual Studio 2008 makes debugging a workflow no more difficult than
debugging any other type of application. (In order to step through your workflow,
the startup project within Visual Studio must be a workflow project. That is
certainly the case in this simple example, but might not be the case in a
“real-world” scenario in which the workflow exists in a library, and the host
project is separate. In that case, you’ll need to configure Visual Studio so
that it starts the host application when you start debugging.)
Investigate the Startup Code
The project template created a simple console application
for you, and the project automatically loaded and ran your workflow. It’s
important to understand exactly how the project does its work, because you’ll
often want to host workflows from other types of applications (from Windows or
Web applications, or perhaps from a Windows Service)—in those cases, you’ll
need to provide your own code to get the workflow running.
To investigate the code that actually does the work starting
up your workflow, in the Solution Explorer window, double-click Module1.vb or
Program.cs. There, you’ll find the following code:
Class Program
Shared WaitHandle As New AutoResetEvent(False)
Shared Sub Main()
Using workflowRuntime As New WorkflowRuntime()
AddHandler workflowRuntime.WorkflowCompleted, _
AddressOf OnWorkflowCompleted
AddHandler workflowRuntime.WorkflowTerminated, _
AddressOf OnWorkflowTerminated
Dim workflowInstance As WorkflowInstance
workflowInstance = _
workflowRuntime.CreateWorkflow(GetType(Workflow1))
workflowInstance.Start()
WaitHandle.WaitOne()
End Using
End Sub
Shared Sub OnWorkflowCompleted(ByVal sender As Object, _
ByVal e As WorkflowCompletedEventArgs)
WaitHandle.Set()
End Sub
Shared Sub OnWorkflowTerminated(ByVal sender As Object, _
ByVal e As WorkflowTerminatedEventArgs)
Console.WriteLine(e.Exception.Message)
WaitHandle.Set()
End Sub
End Class
class Program
{
static void Main(string[] args)
{
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted +=
delegate(object sender, WorkflowCompletedEventArgs e)
{ waitHandle.Set(); };
workflowRuntime.WorkflowTerminated +=
delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(
typeof(WorkflowDemo1.Workflow1));
instance.Start();
waitHandle.WaitOne();
}
}
}
This code, which runs as your application loads, starts by
creating a new instance of the WorkflowRuntime class, which provides a
execution environment for workflows. Every application you create that hosts
one or more workflows must create and instantiate an instance of this class.
The WorkflowRuntime instance later creates workflow instances:
Using workflowRuntime As New WorkflowRuntime()
' Code removed here…
End Using
using (WorkflowRuntime workflowRuntime =
new WorkflowRuntime())
{
// Code removed here…
}
On its own, a Console application simply quits when the code
in its Main procedure completes. In this case, however, you must keep the
application “alive” as long as the workflow is still running. The project
template includes an AutoResetEvent variable that helps keep that application
running until the workflow has completed:
Shared WaitHandle As New AutoResetEvent(False)
AutoResetEvent waitHandle = new AutoResetEvent(false);
The AutoResetEvent class allows threads to communicate with
each other by signaling. In this case, the Console application runs in one
thread, and the workflow runs in a separate thread. The main thread—in this
case, the console application—calls the wait handle’s WaitOne method, which
blocks the console application’s thread until the workflow’s thread calls the
wait handle’s Set method, which allows the main thread to complete.
How does this all happen? Given the WorkflowRuntime
instance, the code adds event handlers for the runtime’s WorkflowCompleted and
WorkflowTerminated events. The WorkflowCompleted event occurs when the workflow
completes normally, and the WorkflowTerminated event occurs if the workflow
completes abnormally (because of an unhandled exception, for example):
AddHandler workflowRuntime.WorkflowCompleted, _
AddressOf OnWorkflowCompleted
AddHandler workflowRuntime.WorkflowTerminated, _
AddressOf OnWorkflowTerminated
' Later in the class:
Shared Sub OnWorkflowCompleted(ByVal sender As Object, _
ByVal e As WorkflowCompletedEventArgs)
WaitHandle.Set()
End Sub
Shared Sub OnWorkflowTerminated(ByVal sender As Object, _
ByVal e As WorkflowTerminatedEventArgs)
Console.WriteLine(e.Exception.Message)
WaitHandle.Set()
End Sub
workflowRuntime.WorkflowCompleted +=
delegate(object sender, WorkflowCompletedEventArgs e) {
waitHandle.Set(); };
workflowRuntime.WorkflowTerminated +=
delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};
When either event occurs, the code calls the wait handle’s
Set method, which allows the console application’s thread to continue running
(in effect, completing the application and allowing the console window to
close). If the workflow terminates abnormally, the WorkflowTerminated event
handler writes the exception to the console window before calling the Set
method. (This is, as you can probably surmise, not terribly helpful—because the
message appears in the window immediately before the window closes, you’ll
never actually see the message if the workflow throws an unhandled exception!)
You’ve investigated all the code provided in the project
template, except the code that actually starts your workflow running. This code
appears between the code that sets up the event handlers, and the code that
calls the wait handle’s WaitOne method:
Dim workflowInstance As WorkflowInstance
workflowInstance = _
workflowRuntime.CreateWorkflow(GetType(Workflow1))
workflowInstance.Start()
WorkflowInstance instance = workflowRuntime.CreateWorkflow(
typeof(WorkflowDemo1.Workflow1));
instance.Start();
This code starts by creating a WorkflowInstance object,
assigning to it the return value of calling the WorkflowRuntime object’s
CreateWorkflow method. By passing the type of the workflow to be created as a
parameter to the CreateWorkflow method, the workflow runtime can determine
exactly which type of workflow to create. Finally, the code calls the Start
method of the workflow instance, which begins executing the workflow at its
first activity. (Sequential workflows have an initial activity; state machine
workflows have an initial state. It’s a subtly different concept, and you’ll
understand it better once you try out a state machine workflow.)
Although you’ll probably want to spend the most time
fixating on the mechanics of the AutoResetEvent object and the wait handle,
please don’t—these features are only necessary for workflows hosted by a Console
application, to keep the application running as long as the workflow hasn’t
completed. When you host a workflow in any other type of application (a Windows
Forms application, for example), you needn’t worry about keeping the
application alive.
Build a Slightly More Useful Workflow
Although it’s important to work through the obligatory
“Hello, World” example as you’ve done, the workflow you built really didn’t do
much. For the remainder of this tutorial, you’ll build a workflow application
with the following features for backing up files in a folder:
- When the workflow starts up, it creates the
required backup folder, if necessary, using a Code activity.
- Using a While activity, it loops through all the
files in the “from” folder.
- Within the activity inside the While activity, a
Code activity performs the file copy.
- The workflow receives its “from” and “to”
folders passed as parameters from the host application.
In setting up this simple workflow, you’ll learn how to use
the While activity, and also how to pass parameters to a workflow from the
host.
In Visual Studio 2008, create a new project, again selecting
Sequential Workflow Console Application as the template. Name the project
BackupWorkflow.
In the workflow designer, drag a Code activity, then a While
activity, and finally, another Code activity into the designer. When you’re
done, the designer should look like Figure 9. Note that each of the activities
displays an error condition: the two Code activities require code to execute,
and the While activity requires you to supply a condition so that it can
determine when to stop executing.
.jpg)
Figure 9. Create this
simple workflow.
The While activity allows you to drop a single activity
within it (note the “Drop and Activity” prompt inside the activity). What if
you want to execute multiple activities in a loop? Although you cannot drop
multiple activities inside the While activity, for this very purpose, WF
supplies a Sequence activity. The Sequence activity acts as a container for
other activities, and as far as the While activity is concerned, it contains
only a single activity once you place a Sequence activity inside it. Although
this workflow only requires a single activity within the While activity, iif
you were to add more than a single activity, you would need the Sequence
activity. On the other hand, adding the Sequence activity adds significant
overhead to the workflow’s execution—therefore, only add a Sequence activity if
you need multiple activities within the While activity. As a “best practice”, consider
minimizing the number of activities within the While activity, if at all
possible..
Drag a Sequence activity inside the While activity. When
you’re done, the workflow should resemble Figure 10.
.jpg)
Figure 11. The
completed layout should look like this.
Configure Code Activities
Double-click codeActivity1, creating the activity’s
ExecuteCode handler. At the top of the code file, add the following statement:
Outside the procedure you just created, but inside the
Workflow1 class, add the following declarations. You’ll use these declarations
to keep track of the “from” and “to” folders, as well as the current file and
total number of files as you’re copying files:
Private currentFile As Integer
Private files As FileInfo()
Private _totalFiles As Integer
Public Property TotalFiles() As Integer
Get
Return _totalFiles
End Get
Set(ByVal value As Integer)
_totalFiles = value
End Set
End Property
Private _toFolder As String
Public Property toFolder() As String
Get
Return _toFolder
End Get
Set(ByVal value As String)
_toFolder = value
End Set
End Property
Private _fromFolder As String
Public Property fromFolder() As String
Get
Return _fromFolder
End Get
Set(ByVal value As String)
_fromFolder = value
End Set
End Property
public string toFolder { get; set; }
public string fromFolder { get; set; }
public int totalFiles ( get; set; }
private int currentFile;
private FileInfo[] files;
In the codeActivity1_ExecuteCode procedure, add the
following code, which initializes the variables:
currentFile = 0
files = New DirectoryInfo(fromFolder).GetFiles
totalFiles = files.Count
' Create the backup folder.
Directory.CreateDirectory(toFolder)
currentFile = 0;
files = new DirectoryInfo(fromFolder).GetFiles();
totalFiles = new DirectoryInfo(fromFolder).GetFiles().Count();
// Create the backup folder:
Directory.CreateDirectory(toFolder);
Select View | Designer to switch back to the workflow
designer. Double-click codeActivity2, and add the following code to the
activity’s ExecuteCode handler. This code retrieves the name of the current
file to be copied, copies it to the “to” folder (overwriting existing files),
and increments the current file counter:
Dim currentFileName As String = _
Path.GetFileName(files(currentFile).Name)
files(currentFile).CopyTo( _
Path.Combine(toFolder, currentFileName), True)
currentFile += 1
string currentFileName =
Path.GetFileName(files[currentFile].Name);
files[currentFile].CopyTo(
Path.Combine(toFolder, currentFileName), true);
currentFile++;
At this point, you’ve set up the Code activities and their
ExecuteCode handlers, but you’re not done: You still need to configure the
While activity, and you need to pass the fromFolder and toFolder values from
the host application. In addition, you need to add code in the host that
reports on the results of executing the workflow.
Configure the While Activity
The While activity in this workflow needs to execute as many
times as there are files in the “from” folder. The code includes the
currentFile and totalFiles variables—you simply need to expose that information
to the While activity.
Select View | Designer. In the designer, select the While
activity. In the Properties window, find the Condition property, select the
drop-down arrow to the right of the property’s value, and select Declarative
Rule Condition (see Figure 11). You have the option of either defining a rule
in the Properties window (Declarative Rule Condition) or creating a condition
in code (Code Condition). For this demonstration, you’ll create the condition
in the Properties window.
.jpg)
Figure 12. Set up the
declarative rule condition.
Click the tiny “+” sign to the left of the Condition
property, expanding the property. Set the ConditionName property to filesLeft.
(Naming the condition allows you to use the same condition in a different place
within your workflow.) Select the Expression property, and then select the
ellipsis to the right of the property. Enter the condition shown in Figure 12.
As you type, note the IntelliSense support. Clearly, the Rule Condition Editor
window is able to retrieve information about the properties exposed by your
workflow as you type. Although Visual Basic developers can enter the expression
using Visual Basic syntax (using the Me keyword instead of this), the editor
converts the syntax to C# syntax before it closes. Click OK to close the
editor.
.jpg)
Figure 13. Create the
While activity’s rule condition.
The rule condition specifies that your workflow should loop
inside the While activity as long as the currentFile value is less than the
total number of files. In effect, you’ve created a simple For loop using the
While activity and a little bit of code. (You might be wondering if there’s
some way to create a For Each loop using an activity. There is, in fact. The
Replicator activity can accomplish this same goal, with less code. You can
learn more about that activity in a later tutorial.)
Configuring Input Parameters
You still need to be able to specify the fromFolder and
toFolder values from the host application. Because you’ll often need to pass
parameters to a workflow, as you start it up, WF provides a standardized
mechanism for passing parameters from the host to a workflow.
As you did earlier, open the Module1.vb or Program.cs file
in the code editor. Currently, the Main procedure creates the workflow instance
using the following code:
workflowInstance =
workflowRuntime.CreateWorkflow(GetType(Workflow1))
WorkflowInstance instance =
workflowRuntime.CreateWorkflow(typeof(BackupWorkflow.Workflow1));
In order to pass parameters to the workflow, you must create
a generic dictionary, using a String type as the key, and an Object type as the
value. Add property name and value pairs to the dictionary, and pass it as a
second parameter in the call to the CreateWorkflow method. The workflow runtime
engine passes the parameters by name to the workflow as it creates the
instance.
Because the workflow you created exposes public fromFolder
and toFolder properties, you can easily pass these parameters from the host
application. To finish your workflow, add the following code to the Main
procedure, replacing the existing line of code that calls the CreateWorkflow
method (feel free to alter the specific folders to match your own situation.):
Dim parameters As New Dictionary(Of String, Object)
parameters.Add("fromFolder", "C:\test")
parameters.Add("toFolder", "C:\backup")
workflowInstance =
workflowRuntime.CreateWorkflow(GetType(Workflow1), parameters)
var parameters = new Dictionary<string, object>();
parameters.Add("fromFolder", @"C:\test");
parameters.Add("toFolder", @"C:\backup");
WorkflowInstance instance =
workflowRuntime.CreateWorkflow(
typeof(BackupWorkflow.Workflow1), parameters);
This technique has its own set of tricks. First of all, the
parameter names must match public properties (not fields) in the workflow’s
class. If you add an invalid property name to the dictionary, you won’t get a
compile-time error—instead, you’ll find out at runtime that your property name
is incorrect. In addition, the property names are case-sensitive, even when
you’re writing code in Visual Basic.
Display Workflow Results
As you’ve seen earlier, the workflow runtime’s
WorkflowCompleted executes once the workflow completes successfully. In
addition, you’ve seen how to pass parameters to the workflow, using a custom
dictionary. You can also retrieve values back from the workflow, in the
WorkflowCompleted event handler: the WorkflowCompletedEventArgs that the .NET
Runtime passes to this event handler exposes its OutputParameters collection.
You can use the name of any public property within the workflow as a string
index into this collection to retrieve the value of the property. To verify this
behavior, in Module1.vb or Program.cs, modify the OnWorkflowCompleted event
handler so that it includes the following code (in C#, the event handler
appears at the end of a long line of code, which hooks up the WorkflowCompleted
event handler using an anonymous method. You’ll find it easier to add this code
if you reformat the existing code so that it looks similar to the
WorkflowTerminated event handler):
Console.WriteLine("Copied {0} file(s)", _
e.OutputParameters("TotalFiles"))
Console.WriteLine("Press any key to continue...")
Console.ReadKey()
WaitHandle.Set()
Console.WriteLine("Copied {0} file(s)",
e.OutputParameters["TotalFiles"]);
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
waitHandle.Set();
Save and run your project. If you’ve followed the directions
carefully, the workflow should copy all the files from the “from” folder to the
“to” folder, and you should see the results of the workflow in the Console
window.
Conclusion
In this tutorial, you’ve learned many of the basic concepts
involved in creating and executing workflows, using the Windows Workflow
Foundation. Of course, the workflows you created are contrived, and exist
simply to demonstrate specific features of WF—you’ll need to consider, as you
begin thinking about incorporating WF into your own environment, what kinds of
tasks lend themselves to running as workflows. Consider this: because WF
supports features like persistence, which allows the workflow to persist its
state to a data store (SQL Server, by default), WF is best suited for
applications in which you have a long-running task that must survive even if
the host machine needs to be rebooted during the task’s execution. For simple
applications like you’ve seen here, WF is truly overkill. For enterprise
solutions in which you have tasks that might not complete for days, or months,
WF provides a perfect solution.
Now that you’ve gotten a taste for what you can do using WF,
take the time to try out the remaining tutorials in this series, and then start
building your own workflows. You’ll be amazed at the power in this rich
framework.
About the Author
Ken Getz is a developer, writer, and trainer, working as a
senior consultant with MCW Technologies, LLC. In addition to writing hundreds
of technical articles over the past fifteen years, he is lead courseware author
for AppDev (http://www.appdev.com). Ken has co-authored several technical books
for developers, including the best-selling ASP.NET Developer’s Jumpstart,
Access Developer’s Handbook series, and VBA Developer’s Handbook series, and
he’s a columnist for both MSDN Magazine and CoDe magazine. Ken is a member of
the INETA Speakers Bureau, and speaks regularly at a large number of industry
events, including 1105 Media’s VSLive, and Microsoft’s Tech-Ed.
Related Links