The Windows Workflow API

This article was originally published in VSJ, which is now part of Developer Fusion.
In any enterprise application a significant portion of the business logic is too complex and sophisticated to be effectively expressed only in terms of classes and relationships. With classes, you can design the entities of the domain such as invoices or products, give each entity a proper behaviour, and perhaps design a model to express dependencies between classes. A number of popular design patterns help you with designing the building blocks of a realistic business and data layer. So, in the end, you may have an invoice class that knows how to create, print, update, and send an invoice.

Armed with a variety of similar objects, can you honestly say you can model some typical business processes in an enterprise scenario? Of course, you can’t. The software description of a business process results from the composition of objects that implement a behaviour. A business process is merely the logical sum of a variety of activities. Each activity represents an action that involves one or more entities. The invoice, for example, is never a standalone object in a reasonable application context. Instead, it will typically result from a chain of events that include a client request, an order, some activity, and then a payment. So, how would you model a business process of any complexity?

Since a business process is logic applied to objects, you can certainly describe the process using classic code, where classes model both entities and the desired flow of activities. The more complex the process, the less appropriate such a solution would be. First off, complex logic is challenging to model and highly error-prone. In addition, a business process has an inherently evolving nature and architects should always favour a solution that is flexible enough to accommodate changes dynamically with limited impact on existing code and with the possibility of running quick and effective regression tests.

To put it succinctly, traditional programming languages are not the ideal tool to model business processes. To effectively model a business process, you might want to create a workflow.

Workflow-driven Applications

A workflow can be defined as the sequence of steps and connections that take you from a starting point to an end point. In the middle, steps and connections describe a process and express some logic. A workflow describes the flow that leads to some results. The concept of a workflow is somewhat abstract and doesn’t necessarily resemble some concrete development API.

The workflow can be seen as a software program written in a meta programming language where the set of instructions is larger and more powerful than in C# or C++. With a workflow API, you describe the process using activities and their connections, dependencies, and relationships. Where do you get such a workflow API?

A number of third-party companies have provided various workflow products for a considerable time. Products may differ in their runtime capabilities, set of supported activities, and because they specialize in one vertical market or another. At its core, a workflow API is mostly made by a toolbox of activities that, combined together, allow architects and developers to design and create realistic flows of work inside business processes.

For years, no general-purpose workflow API existed in Windows, apart from third-party commercial products. Finally, with the advent of the .NET Framework 3.0 (formerly known as WinFX), a workflow API is making its debut on the Windows platform.

Introducing Windows Workflow Foundation

Windows Workflow Foundation (WF) is one of the three new pillars of the .NET Framework 3.0, along with Windows Presentation Foundation (WPF) and Windows Communication Foundation (WCF).
  • WPF is the new Windows presentation subsystem and allows all sorts of user interface functionalities that are not possible or just impractical to code with Win32 and the .NET Framework 2.0 and earlier versions. WPF uses an XML dialect (known as XAML) to describe the user interface that is parsed and processed by a rich rendering engine based on DirectX.
  • WCF is the new framework for building service-oriented applications. It unifies and extends a number of existing Microsoft connectivity and messaging technologies (ASP.NET Web services, .NET Remoting, MS Message Queue) under a single programming model.
  • WF is used to express any complex logic as a .NET assembly. The workflow can represent either a sequential process or a state-machine process in which there are no starting and end points, replaced with a starting and an ending state with related transitions and events.
With the .NET Framework 3.0, you can use WF to create client applications to consume workflows. Note, though, that workflows can also be consumed from within ASP.NET and Windows Forms applications. You can use WCF components to encapsulate workflows and expose them as “services”. Likewise, note that a workflow can also be exposed as a more traditional ASP.NET web service.

Expected to ship in 2007, the .NET Framework 3.0 is currently available in Beta 2 form and works natively on Windows Vista equipped machines. However, it is also supported on Windows 2003 Server and Windows XP operating systems through an ad hoc runtime engine. Let’s get to know more about WF and explore its architectural facts.

Fast Facts

A managed framework for creating workflow applications in Windows, WF is made of a class library and a runtime engine. It lets you compose workflows through “visual” instructions in much the same way you build ASP.NET pages using server controls or Windows desktop applications using Windows Forms controls. Building blocks of WF applications are special components known as “activities”.

You assemble a workflow in a special designer tool hosted in Visual Studio 2005. The designer comes with a toolbox where all built-in activities are listed. All that developers have to do is pick up activities from the toolbox and drop them on the target workflow surface. In its final form, a workflow looks like the sample in Figure 1.

Figure 1
Figure 1: A sample sequential workflow created with the WF Visual Studio 2005 designer

The source code of a WF workflow describes constituent activities and their connections and properties. This information can be serialized in either of two ways – using a class (default) or using an XML schema. Choosing either doesn’t pose any additional issues of performance as it merely regards the serialization format of the workflow and the type of input that gets passed to the workflow compiler. If you write the workflow as a class, the compiler gets ready-to-use information; if you opt for XML, the compiler receives information that it has to parse first and transform into compilable classes.

Using the class-based approach, you save the workflow as a pair of partial classes persisted in different files – workflow1.cs and workflow1.designer.cs. As in Windows Forms applications, the designer file lists the constituent activities of the workflow and their properties, whereas the first file contains any behavioural code. The workflow1.cs file can be considered as the code-beside file of the workflow object. According to the XML-based approach, you still have a code-beside file with the same characteristics, but resort to an XML file to describe the child elements of the workflow. The XML schema is known as XOML. Here’s a code snippet that shows the XOML internal structure:

<SequentialWorkflowActivity
	x:Class=”Samples.Workflow1”
	x:Name=”Workflow1”
xmlns:x=”http://schemas.microsoft.com/
	winfx/2006/xaml”
xmlns=”http://schemas.microsoft.com/
	winfx/2006/xaml/workflow”>
	<CodeActivity
		x:Name=”codeActivity1”
		ExecuteCode=”MyCode” />
		<IfElseActivity
			x:Name=”ifElseActivity1”>
			<IfElseBranchActivity
	x:Name=”ifElseBranchActivity1” />
			<IfElseBranchActivity
	x:Name=”ifElseBranchActivity2” />
		</IfElseActivity>
	:
</SequentialWorkflowActivity>
As you can guess, each tag in the markup grossly maps to an activity. An activity, in turn, is just a class defined in the WF class library. Any method or code referenced by the XOML is conveniently located in the workflow1.xoml.cs helper file. This approach to serialization closely resembles the format of ASP.NET pages, where you have an XML-based description of the page controls with any page relevant code going into a separate code-beside file.

The HelloWorld workflow

Let’s take a look at some workflow source code. The code snippet below illustrates the world’s simplest sequential workflow.
public partial class Workflow1:
	SequentialWorkflowActivity
{
// Private members
	private string lastName;
// Code-behind
	private void
		codeActivity1_CodeHandler(
		object sender, EventArgs e)
	{
		MessageBox.Show(“Hello, “ +
			lastName);
		}

// Public property used for I/O
	public string LastName
	{
		get { return lastName; }
		set { lastName = value; }
	}
}
A sequential workflow is a class that inherits from the SequentialWorkflowActivity class and defines private and public members – fields, properties, methods, and events. The list of activities is defined visually and persisted in the designer class. The preceding code represents the code-beside file of a workflow that counts just one Code activity. The Code activity defines a piece of application-specific code that runs as soon as the execution flow reaches the component. When this happens, the code in the handler executes. The sample workflow includes a public property – LastName – filled with the input data transmitted by the host application at initialization time. More complex and significant workflows differ from such a simple one because of the larger number of activities they incorporate to implement specific actions and provide flow control instruments.

A Tour of the WF Activities

Figure 2 illustrates the content of the WF toolbox when a sequential workflow is selected in the Visual Studio 2005 designer.

Figure 2
Figure 2: Available activities for a sequential workflow

The whole set of activities can be put into five categories – control flow, execution, events, web services, and state transition. This last category is specific of state-machine workflows.

In the control flow category fall activities that control the sequence in which activities execute and the runtime conditions that determine a given code path. Execution activities can be used to terminate or suspend a workflow or throw an exception in case of severe errors. They can also be used to execute ad hoc code and launch an external workflow. Note that in this case, though, the external workflow runs asynchronously, and no attempt is ever made to synchronize it with the parent. Events activities can stop the workflow and make it wait for external events fired by the host environment. Likewise, events activities can be used to add a delay and fire an event to the host application. Finally, the web service activities can be used to expose the workflow as a public ASP.NET web service and to invoke an external web service programmatically.

Exposing a workflow as a web service has a number of advantages. In first place, you publish the workflow so that it can be accessed over the network as an independent piece of code. Next, by binding it to the HTTP protocol you can easily consume it from within any host platform that supports the HTTP protocol and understands SOAP and XML. Table 1 provides a brief description of the main workflow activities.

Table 1: In-box activities supported by Windows Workflow Foundation
Activity Description
Code Enables you to add managed and non-blocking code to the workflow to perform custom actions.
Compensate Enables you to call code to reverse or to compensate for operations already performed by the workflow when an error occurs.
ConditionedActivityGroup Executes a set of child activities conditionally, based on criteria specific to each activity.
Delay Delays the workflow execution for the specified number of seconds.
EventDriven Waits for an external event.
FaultHandler Enables to handle an exception of a specified type.
IfElse Enables the workflow to conditionally execute one of several alternative branches.
InvokeWebService Enables the workflow to invoke a web service method. You specify the proxy class to use (via WSDL) and the name of the method you want to invoke. Both synchronous and asynchronous calls are supported.
InvokeWorkflow Enables the workflow to start another workflow in a fire-and-forget manner.
Parallel Enables your workflow to perform two or more operations independently of each other. The activity waits for both operations to terminate before continuing.
Policy Enables you to represent and execute a collection of rules.
Replicator Enables the workflow to create an arbitrary number of instances of a given activity and execute them either sequentially or concurrently.
Sequence Defines a set of child activities that execute in sequence.
SetState In a state machine workflow, specifies a transition to a new state.
Suspend Suspends the operation of your workflow to enable intervention in the event of some error condition.
Terminate Terminates immediately the operation of your workflow in the event of any abnormal situation.
Throw Throws an exception of the specified type.
TransactionScope Groups some child activities in a transaction.
WebServiceInput Enables the workflow to receive SOAP calls.
WebServiceOutput Enables the workflow to generate SOAP responses.
While Enables the workflow to execute one or more activities while a condition is met.

In addition to the built-in set of activities, new and custom activities can be created programmatically by simply deriving a new class either from the Activity base class or from any of the existing activities.

Hosting workflows in client applications

Even though it is implemented as a class and compiled to an assembly, a workflow should not be used as an ordinary class. In particular, all instances of workflow types used by an application should run inside a runtime engine – the workflow runtime. The workflow runtime manages the lifetime of all the associated workflow instances. The runtime, for instance, is responsible for creating new instances of workflow types. You never use the new operator with a workflow type, but ask the runtime to return a new instance of a given type:
WorkflowRuntime wr =
	new WorkflowRuntime();
// Add events
wr.WorkflowLoaded += new
EventHandler<WorkflowEventArgs>(
	wr_WorkflowLoaded);
wr.WorkflowCompleted +=
	new EventHandler<
	WorkflowCompletedEventArgs>(
	wr_WorkflowCompleted);

// Add system SQL state service
SqlWorkflowPersistenceService
	stateService;
stateService = new
	SqlWorkflowPersistenceService(
	“Data Source=...;
		InitialCatalog=...;UID=...;”);
wr.AddService(stateService);

// Start
wr.StartRuntime();
To host a workflow in a client application, you start by getting a new instance of the WorkflowRuntime class and register a few event handlers with it. As a minimum, you add a handler to the WorkflowCompleted and WorkflowTerminated events. The former fires when the workflow is complete; the latter reaches your application when the workflow is abruptly terminated due to an exception or a user action. The next step involves the optional injection of external services. A runtime service is a piece of code that adds new capabilities not directly supported by the runtime and not required by all workflow types. Examples of service include state persistence and tracking, thread scheduling, external data exchange.

In the preceding code snippet, you see the SqlWorkflowPersistenceService in action. This service enables the runtime to persist and freeze the state of a running workflow when this gets idle or stops waiting for an external event. The service serializes the workflow object to the provided database and deserializes it back when needed. Schema and type of the database (be it SQL Server, Oracle or any other) are up to the development team. The default persistence service uses a particular SQL Server database, but by deriving a class from SqlWorkflowPersistenceService you can make it use any other storage medium.

Workflows model business processes and in real-world processes there’s often some point in which human intervention is required. But humans sometimes introduce delays of days or weeks. What should you do? Keep the workflow instance running in the runtime indefinitely? When idleness is detected, the persistence service and the runtime freeze the workflow until programmatically resumed. The tracking service monitors internal events and state changes of the workflow, whereas the thread scheduler ensures that the workflow execute synchronously within ASP.NET hosts without blocking valuable pooled threads.

It is essential to note that you can have only one workflow runtime per AppDomain. Once you have a properly configured runtime object, you can actually create a workflow instance, as shown below:

Type t = typeof(Samples.Workflow1);
WorkflowInstance inst =
	wr.CreateWorkflow(t, parameters);
inst.Start();
A running workflow instance is identified with a unique GUID. A workflow instance can accept input parameters from the outside world and return values.

Exchanging data with the outside world

Any input value that a workflow type may accept from the caller must be mapped to a public property on the workflow class. Input parameters are to be grouped in a name/value collection object and passed as the second argument of the CreateWorkflow method.
Dictionary<string, object> parameters;
parameters = new
	Dictionary<string, object>();
parameters.Add(“EmployeeID”,
	listEmp.SelectedValue);
You first create a new generic dictionary where the name is a string and the value is of type object. Next, you add as many items as there are input values to pass. The name of the item, and the type of the associated value, must match a public property on the workflow class. Workflow return values are handled similarly. You make sure that any returnable value is stored in a public property. All public properties are then copied into a collection named OutputParameters and passed to the client with the WorkflowCompleted event:
void wr_WorkflowCompleted(
	object sender,
	WorkflowCompletedEventArgs e)
{
	MessageBox.Show(
		e.OutputParameters[
		“ReturnValue”]);
}
The OutputParameters collection contains the final value of all public properties, including those set with input values.

State-machine Workflows

A state machine workflow is made up of states and rules that make the workflow transition from one state to the next. Each state is composed of one or more event handlers. Handlers control the transition to that state and can either be based on a Delay activity or an external event (EventDriven activity). Each event handler also can contain a SetState activity that is used to transition from one state to another. A state machine workflow doesn’t have a starting and an ending point. Instead, it has two properties that designate the initial and final state. When a state machine workflow is created, it is put into the initial state. When the state machine reaches the final state, its execution is complete, see Figure 3.

Figure 3
Figure 3: A sample state-machine workflow in the WF Visual Studio 2005 designer

Using a sequential or a state-machine workflow depends on the characteristics of the process to model and also your perception of it. In general, a state-machine is preferable when the entities in play tend to evolve based on events and not necessarily from top to bottom. For example, if you model an order processing system as a sequential workflow you are in trouble as soon as you get to consider ways to update an order and make it move back to an earlier state. When many events and states are to be considered, a state-machine seems to be a more appropriate tool.

Conclusion

Designed to become the workflow framework for new and existing Microsoft products, WF delivers a unified workflow model and a set of tools that replace many proprietary libraries and products. Seen in this way, Windows Workflow Foundation is also of significant importance to third-party vendors because it makes it possible for them to use WF as the underlying machinery, freeing resources and focussing creativity on higher level tasks to design more specific features.


This article has presented some key architectural facts about WF but only scratched the surface of the whole topic. For more information and additional resources, take a look at msdn.microsoft.com/workflow.

Dino Esposito is a Solid Quality Learning mentor and prolific author. He is the author of the two volumes Programming Microsoft ASP.NET 2.0 (Microsoft Press, 2005), writes the Cutting Edge column for MSDN Magazine, and regularly contributes to a variety of developer magazines. He will also be speaking at the 10th annual DevWeek conference at the end of February.

You might also like...

Comments

About the author

Dino Esposito United Kingdom

Dino Esposito is an instructor for Solid Quality Mentors, and a trainer and consultant based in Rome. He is the author of various books, including Windows Shell Programming, Instant DHTML Script...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Theory is when you know something, but it doesn't work. Practice is when something works, but you don't know why. Programmers combine theory and practice: Nothing works and they don't know why.”