
A Windows Workflow Tour
Microsoft's Windows Workflow Foundation is one piece of the new .NET 3.0 platform. The other major additions in .NET 3.0 include Windows Presentation Foundation, or WPF, and Windows Communication Foundation, or WCF. Microsoft will support Windows Workflow (WF) on Windows XP, Windows Server 2003, and Windows Vista.
Support for current and future Microsoft platforms means WF could reach near ubiquity over time. We can use WF in smart client applications, and in simple console-mode programs. We can also use WF in server-side applications, including Windows services, and ASP.NET web applications and web services. WF will make an appearance in several of Microsoft's own products, including Windows SharePoint Services and Microsoft Biztalk Server. We will now look at an overview of the essential features of Windows Workflow.
Activities
The primary building block in Windows Workflow is the activity. Activities compose the steps, or tasks in a workflow, and define the workflow. We can arrange activities into a hierarchy and feed activities to the workflow engine as instructions to execute. The activities can direct workflows involving both software and humans.
All activities in WF derive from an Activity
base class. The Activity
class defines operations common to all activities in a workflow, like Execute
and Cancel
. The class also defines common properties, like Name
and Parent
, as well as common events like Executing
and Closed
(the Closed
event fires when an Activity is finished executing). The screenshot below shows the Activity class in the Visual Studio 2005 class designer:

WF ships with a set of ready-made activities in the base activity library. The primitive activities in the library provide a foundation to build upon, and include control‑flow operations, like the IfElseActivity
and the WhileActivity
. The base activity library also includes activities to wait for events, to invoke web services, to execute a rules engine, and more.
Windows Workflow allows developers to extend the functionality of the base activity library by creating custom activities to solve problems in their specific domain. For instance, pizza delivery workflows could benefit from custom activities like SendOrderToKitchen
or NotifyCustomer
.
All custom activities will also ultimately derive from the base Activity
class. The workflow engine makes no special distinction between activities written by Microsoft and custom activities written by third parties.
We can use custom activities to create domain‑specific languages for building workflow solutions. A domain‑specific language can greatly simplify a problem space. For instance, a SendOrderToKitchen
custom activity could encapsulate a web service call and other processing logic inside. This activity is obviously specific to the restaurant problem domain. A developer will be more productive working with this higher-level abstraction than with the primitive activities in the base activity library. Even a restaurant manager will understand SendOrderToKitchen
and might arrange the activity in a visual workflow designer. It will be difficult to find a restaurant manger who feels comfortable arranging WhileActivity
and InvokeWebServiceActivity
objects in a workflow designer.
C#, VB.NET, and XML are general-purpose languages and have the ability to solve a wide array of different problems. We can use C# to develop solutions for pizza restaurants as well as hospitals, and the language works equally well in either domain. A domain-specific language excels at solving problems in a particular area. A domain-specific language for restaurant workflow would boost productivity when writing software for a restaurant, but would not be as effective when writing software for a hospital.
Visual Studio 2005 Extensions
Microsoft also provides the Microsoft Visual Studio 2005 Extensions for Windows Workflow. These extensions plug into Visual Studio to provide a number of features, including a visual designer for constructing workflows. A screenshot of the visual designer is shown on the next page.

The designer uses the same windows we've come to love as Windows and web form developers. The Toolbox window will list the activities available to drag onto the design surface. We can add our own custom activities to the Toolbox. Once an activity is on the design surface, the Properties window will list the activity's properties that we can configure, and the events we can handle. The Toolbox window is shown below:

The WF designer can generate C# and Visual Basic code to represent our workflow. The designer can also read and write eXtensible Application Markup Language (XAML, pronounced zammel). XAML files are valid XML files. XAML brings a declarative programming model to Windows Workflow. Here is the XAML generated by the designer for the workflow we saw earlier:
<SequentialWorkflowActivity xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow" x:Class="HelloWorld.HellowWorldWorkflow" > <CodeActivity x:Name="codeActivity1" ExecuteCode="codeActivity1_ExecuteCode_1" /> </SequentialWorkflowActivity>
Our workflow is trivial and contains only a single activity inside—a CodeActivity
. When the workflow engine executes the CodeActivity
, the CodeActivity
will invoke a method specified by the ExecuteCode
attribute. Our XML also includes special XML namespace directives. We'll cover XAML and these namespaces in Chapter 2.
XAML is not a technology specific to Windows Workflow. As an "extensible application" markup language, XAML is also present in Microsoft's presentation framework—Windows Presentation Foundation (WPF). In WPF, XAML declaratively constructs a rich user interface consisting of not only buttons and labels, but also animation storyboards and data templates.
One important capability of declarative XAML is the ability to join forces with imperative code in a partial class. Partial classes, introduced in .NET 2.0, are a feature available to both Visual Basic and C# developers. Partial classes allow the definition of a class to span more than one file. The XAML above will transform into a partial class by the name of HelloWorldWorkflow
. We control the name of the class from XAML with the x:Name
attribute in the root node. We can add members to the generated class by defining a class with the same name and with the partial
keyword.
public partial class HelloWorldWorkflow : SequentialWorkflowActivity { private void codeActivity1_ExecuteCode_1(object sender, EventArgs e) { // ... } Windows WorkflowVisual Studio 2005 Extensions}
In this example, we are adding the codeActivity1_ExecuteCode_1
method as a member of the same class (HelloWorldWorkflow
) produced by the XAML.
Another job of the workflow designer is to provide validation feedback for the activities in a workflow. Each activity can define its own design-time and run-time validation. The designer will flag an activity with a red exclamation point if the activity raises validation errors. For example, a CodeActivity
will display a red exclamation point until we set the ExecuteCode
property. Without a method to invoke, the CodeActivity
is useless, but the validation catches this problem early and provides visual feedback.
The designer also provides debugging features. We can set breakpoints on an activity in the workflow designer. When execution stops, we can look at the Call Stack window to see the activities previously executed in the workflow instance. The debugger commands Step In, Step Out, and Step Over all work intuitively; for instance, the Step In command will move to the first activity inside a composite activity, while Step Over executes the entire composite activity and moves to the next sibling.
The workflow designer allows customization of its design surface via themes. A theme defines the background colors, fonts, grid lines, and border styles to use on the design surface. We can even specify color and border styles for specific activity types. Through Visual Studio, we can create new themes, or modify existing themes.
All this styling ability isn't just to make the designer look pretty in Visual Studio, however. The WF designer is a component we can host inside our own applications. The ability to host the designer opens a number of interesting possibilities. First, we can host the designer and allow the non-developer types (a.k.a. business people) to design and edit workflows. By providing custom activities, we can match the vocabulary needed to build a workflow with a vocabulary the business people will understand (a domain-specific language). By providing custom themes, we can match the designer look with the look of our application.
The Windows Workflow Runtime
One perspective for Window Workflow is to view the workflow activities as instructions, or opcodes, for a workflow processor to execute. In Windows Workflow, the processor is in the WF runtime. To start a workflow party, we first need a host for the runtime and workflow services.
Windows Workflow is not a stand-alone application. Like ASP.NET, WF lives inside a handful of assemblies (most notably for this topic, the System.Workflow.Runtime.dll
assembly). Like the ASP.NET runtime, WF needs a host process to load, initialize, and start its runtime before anything interesting can happen. Unlike the traditional server-side usage of ASP.NET, however, WF will be useful in a variety of different hosts. We can host WF in a smart client application, a console application, or a Windows service, for instance.
The class diagram in the screenshot below features the primary classes we use to execute workflows in WF.

Creating an instance of the WorkflowRuntime
class and calling StartRuntime
is all we need to spin up the workflow execution environment. WorkflowRuntime
defines methods that allow customization of the execution environment. The class also defines events we can listen for during execution. The runtime will fire an event when workflows finish execution, abort, turn idle, and more.
Once we've created an instance of the runtime, we can create workflows with the CreateWorkflow
method. The CreateWorkflow
method returns an object of type WorkflowInstance
. The WorkflowInstance
class represents an individual workflow. The Start
method on the workflow instance object will begin the execution of a workflow. If an exception occurs, the workflow will invoke the Terminate
method (which leads to the runtime raising a WorkflowTerminated
event). A typical sequence of calls is shown in the screenshot next.

The WorkflowRuntime
and WorkflowInstance
classes are arguably the most important classes needed at run time, but they are not the only classes available. Other classes inside the WF assemblies provide important services to the workflow runtime. Chapter 5 will cover these services in detail, but the following provides a brief introduction.
The WorkflowRuntime
class provides only the basic features for executing workflows. Earlier, we mentioned important features we'd like to see in a workflow engine, like the ability to track active workflows and deactivate idle workflows. Don't worry, these features are available through an extensibility mechanism of WorkflowRuntime
— the AddService
method.
AddService
allows us to make one or more services available to the runtime. These services might be custom services we've written specifically for our domain, like a custom scheduling service, or they might be services already written by Microsoft and included with WF. Let's continue our tour by looking at the services already available.
A scheduling service controls threads the runtime needs to execute workflows. The DefaultWorkflowSchedulerService
creates new threads to execute workflows. Because the threads are separate from the host application, the workflows do not block any application threads and execute asynchronously. The maximum number of simultaneously executing workflows is configurable.
A second scheduling service, the ManualWorkflowSchedulerService
, is available when the host application is willing to donate threads to the workflow runtime. Donating a thread to the runtime is a useful technique in server‑side applications, like ASP.NET web applications and web services. Server-side applications typically pull a thread from a pool to service each client request. It makes sense to loan the thread to the WF runtime, and let the runtime execute the workflow synchronously on the existing request thread instead of using two threads per request, which could reduce scalability.
As with all services in Windows Workflow, you can define your own scheduling service if the built-in services do not fit your requirements.
A transaction service, as the name might imply, allows the runtime to keep the internal state of a workflow consistent with the state in a durable store, like a relational database. The default transactional service is an instance of the DefaultWorkflowTransactionService
class. Activities inside a running instance of a workflow, and the services operating on the same instance, can all share the same transaction context.
WF relies on the implementation of transactions in .NET's System.Transactions
namespace. The Transaction
class offers a lightweight, auto-enlisting, and promotable transaction. The transaction can start as a local transaction, and later the runtime can promote the transaction to a heavyweight, distributed transaction if needed.
A persistence service is responsible for saving the state of a workflow to a durable store. The SqlWorkflowPersistenceService
service saves the state of a workflow into a SQL Server database. Persistence is required for long‑running workflows, because we can't have an invoice-processing workflow in memory for 30 days till the customer's payment arrives. Instead, the runtime can persist the state of the workflow to a durable store and unload the instance from memory. In 30 days (or hopefully, less), the runtime can reload the workflow instance and resume processing. The WF runtime will automatically persist a workflow that is idle or suspended when a persistence service is present.
The SqlWorkflowPersistenceService
will work with SQL Server 2000 or any later version of Microsoft SQL Server, including the free MSDE and Express editions. Of course, we'll need a database schema that the persistence service understands. In Chapter 5 we will see how to use the T-SQL installation scripts provided by the .NET 3.0 installation.
While a scheduling service is responsible for selecting threads for a workflow to run on, a tracking service is responsible for monitoring and recording information about the execution of a workflow. A tracking service will tell the runtime the type of information it wants to know about workflows using a tracking profile. Once the service establishes a profile, the service can open a tracking channel to receive events and data. Chapter 5 includes more details on tracking profiles and channels.
WF includes a SqlTrackingService
class that stores tracking data into a SQL Server database. The service will use the previously discussed transactional service to ensure the tracking data for a workflow is consistent with the state of the workflow it's tracking. The runtime does not start a tracking service by default, but we can programmatically add a tracking service (or configure a tracking service with an application configuration file) for the runtime to use.
Now we've covered all the basic features of WF, so let's put the software to work.