Introduction
With the advent of .NET Framework 3.0 (formerly WinFX), terms like Windows
Presentation Foundation (formerly Avalon), Communication Foundation (formerly
Indigo), Workflow Foundation (formerly WWF) and Cardspace (formerly InfoCard)
are everywhere. The .NET Framework 3.0 also includes a powerful
general-purpose object initialization language known as XAML (eXtensible
Application Markup Language). What Microsoft is really putting stress on is
creating compelling user experiences and secure, seamless communication across
boundaries.
In this series of articles, I will be explaining and going in
depth with some of the core components of .NET Framework 3.0.
Let's start with Windows Workflow Foundation (WF).
Background (optional)
I assume you have basic knowledge of the .NET Framework. I will try and cover
most of the concepts as soon as they arise.
Workflow and its types
In
the business world, workflow is simply a business process (independent of
technology) necessary to complete a task. There can be various steps involved in
any business process that can be either optional or required. So simply put,
"workflow" is just the flow of work.
If we add more to it, "flow of work"
can be either in a sequential manner (i.e. steps are performed one
after another), or there could be several points in the flow where some
decisions need to be made. Since a flow cannot move from one point to another
without some criteria being met, we have a state-based workflow.
Thus, we can simply say there are two types of workflow:
- Sequential
- State
Machine
A state-based workflow waits on external entities to perform some action before
moving on to the next step. On the other hand, a sequential workflow is just a
continuous flow of operations which might include branching,
but steps in the sequential workflow don't wait for an external entity to perform
the operation, and then continue.
Within a workflow, branching is done when a decision is to be made. For each
branch in the workflow there must be two alternatives, either true, or false. You
cannot just stop the workflow to make a decision at any point.
Which workflow to choose
Sequential workflow follows the traditional style of thinking - i.e. as long as
the process is simple and stays in the boundary then a sequential workflow
will work.
On the other hand, state machine workflows deal with different states of the
workflow. A process which involves several different iterations before
getting into the final shape is a candidate for being a state machine workflow.
Why Workflows and WF
One of the biggest reasons for creating a workflow is that you are actually
creating
a model. Most of the business processes have some sort of model
associated with them, whether it is use-cases, UML diagrams or a simple flow
chart. In a process you always have some flow and thus, there will always be some
steps involved in its execution.
With WF, model and workflow are one
and the same. You use pieces of a business process to make a
workflow and you piece together the workflow, which makes a model. Before WF you
would make couple of UML diagrams, drawing flow-charts, writing
pseudo code, explaining in bulleted text how an operation should work and then
finally you will get to writing the code, whereas with WF when you are
modeling the business process you are also building the application!
Windows Workflow Foundation (WF)
As discussed earlier, WF is part of the Microsoft's new programming model .NET
Framework 3.0. It enables business processes to be expressed
graphically and linked directly to business logic. With WF, workflows can be
expressed in either:
- Declarative
XAML.
- Imperative
code using any .NET targeted language.
- Developed
visually through Visual Studio Designer.
The WF programming model is made up of a number of exposed APIs that are
encapsulated in the Microsoft .NET Framework 3.0 namespace called
System.Workflow
Let's have a quick look at the WF architecture.
Designer
The most convenient way to interact with the namespace is of course through the
workflow designer. You just create a workflow, drag and drop
activities, and there you have it. A complete working model!
Activities
Every workflow is made up of a set of activities (steps/tasks). These activities
facilitate the business process or are part of the business process. In
terms of WF, the activities are the actual work units required to carry out a
workflow. WF allows you to create your own custom activities and your
own library, which will be done in the coming article.
RunTime Engine
The next component of the WF is the WF runtime engine. The WF runtime engine
executes workflow made up of activities created with VS2005
Workflow Designer. The runtime engine includes three basic services:
- Scheduling
(schedules the execution of activities within a workflow)
- State
Management (allows the state of the workflow to be persisted instead of storing
it in some other mechanism like database)
- Rules
(executes policy activities i.e., add rules on the workflow against certain
activities in order to control the flow)
Host Process
A WF has no executable environment and requires a host process within which it
can execute. They are not applications themselves, rather, they require an
application where they can reside. This host process can be a Windows
Application or an ASP.NET Web application.
Installation
Assuming you have VS 2005 installed and the latest .NET Framework, in order to
work with the WF you simply need to download and install the
following
components:
After installing the components, within VS 2005 you will have new project types
and will be able to import and use the namespace.
Fig. 01
Getting Started with WF
The Sequential Workflow Console Application and State Machine
Workflow Console Application provides the workflow model for the two types of
workflow that can be created within WF: sequential and state machine. The first
step to create a workflow application is to select a
workflow model, and then you need to add activities to that model. There isn't
much difference between each of the project templates. The difference between
the console application and library is just that the console application
contains a sub main method which is used to start the workflow. Let's have a look
at the design areas of various project templates available in
WF:
Fig. 02
Before getting into further details it's important to understand the various
activities that are available in the WF. WF provides you with more than a dozen
basic set of activities which I will briefly discuss below in order to have a
better understanding of WF.
- Code
Activity: The Code Activity allows you to add your own VB or C# code to the
workflow. The actual code in the Code Activity resides in a "code beside" and
gets compiled with the workflow.
-
Compensate Activity: This is an error activity and can be added to an
exception handler activity only. This activity is to roll back the changes made
by the workflow in case an error has occurred. You can call it as equivalent to
rolling back a transaction.
-
Conditioned Activity Group: This is a conditional activity that executes
other activities based upon some condition that applies to the group or the
activities attached to the group.
- Delay
Activity: This activity allows you to build interval-based pauses into a
workflow. You may call it as a timer activity that will set duration so that the
workflow will pause before continuing to execute.
- Event
Driven Activity: This is a flow activity that contains other activities that
are to be executed when an event occurs.
- Fault
Handler Activity: This is an error handling activity just like you have
a
catch
block in your code. It can have various activities that are
fired when an
exception is occurred, including a Compensate Activity.
- IfElse
Activity: This is a conditional activity just like you have
If
Else
blocks
in your application. You can have a branch of activities based on a certain
condition.
- Invoke
Web Service Activity: This activity can invoke a specific web method of a
web service using proxy class. It can pass and receive parameters.
- Listen
Activity: This activity is a composite activity. It requires a minimum of two
event driven activities.
- Parallel
Activity: This is again a composite activity which requires minimum two
sequence activities. This activity ensures the parallel execution of the
sequence activities and is not completed until all the sequence activities that
make up the parallel activity are complete.
- Policy
Activity: This activity represents a collection of rules. A rule has a
condition and an action or actions that are to be taken when the condition is
met. It allows having a rule-based workflow rather than setting up an IfElse based
workflow which can get messier.
- Replicator
Activity: This is also a conditional activity. Just like you have
For
Each
statement in your application. It actually creates a number of instances of an
activity while running which it must complete before the replicator activity can be
completed.
- Sequence
Activity: This is also a composite activity which is comprised of several
sequential activities. It provides an easy way to link up those activities which
are to be executed in a sequence.
- Set State
Activity: This is a flow activity that is used to specify changeover to a
new state within a state machine workflow.
- State
Activity: This is a flow activity. This activity represents a State within a
state machine workflow. For example, when an event is handled in a state machine
workflow, a different state activity is inserted to handle that event.
- State
Initialization Activity: This activity is part of a State activity that is
made up of other activities that are to be executed when the state activity is
initialized.
- Suspend
Activity: This is a flow activity and can pause the operation of a workflow
to allow intervention to occur if an error condition requiring special attention
is raised in the execution of workflow. An error is logged against this activity
and a workflow that is paused can still receive messages but those messages are
queued.
- Terminate
Activity: This activity immediately ends the execution of workflow if an
error is raised. This activity also logs the error but unlike suspend activity
it stops the execution of workflow.
- Throw
Activity: This is an error handling activity like you have
Throw
statements
in your application. You can use this activity to throw an exception from one
workflow or an activity to another.
- Transaction
Scope Activity: This activity offers transaction support. All activities
that make up a transaction are placed in this activity.
- While
Activity: This is a conditional activity and is just like a
While
statement
in our application. It executes another activity until a condition is met. The
condition can be either a code based or simply a rule based condition.
Workflows and Activities
All workflows and activities are classes. If we use a basic OOP definition,
a programming language class is nothing but a real world construct
that encapsulates related variables (properties) and methods (functions or
stubs).
As discussed earlier, the namespace Workflow is the newly added namespace in
Microsoft .NET Framework 3.0 under the System namespace for
building workflow applications. There are actually three assemblies that
constitute this namespace i.e. Activities, ComponentModel and Runtime. You
can find them physically located in your GAC.
Fig. 03
Explaining each and every bit of information in these namespaces will not be
feasible for me, you can refer to MSDN for that. However, just to give you an idea
we will just discuss a few of these briefly:
Assembly | Namespace | Description |
Workflow.Activities | Workflow.Activities | The Activities namespace contains all those classes that make
up our available activities with the WF designer. |
| Activities.Rules | This namespace works with the Policy Activity and encapsulates all those
classes that are required for rule based workflow.
|
Workflow.ComponentModel
| ComponentModel
| This namespace provides the base classes, interfaces and core modeling
constructs that are used to create workflows and activities.
Under the ComponentModel namespace it's the Activity class which is the fundamental
building block of workflows.
|
Workflow.Runtime
|
| This assembly provides a runtime and hosting environment for your workflow.
|
Raise the curtains
Enough with the background talking; it's time to wrap up
the sleeves and see some practical code examples.
Sequential Workflow
Open up your VS 2005 and under File > New > Project >
Workflow, you can create a new Sequential Workflow Application. When you
create a new workflow in C# the file which is used to host the console application
is
called Program.cs, whereas in VB it is Module1.vb
After creating a new project we have deleted our
Workflow1.cs file and instead added a new item for creating our sequential
workflow.
Fig. 04
Just to clarify here: WPF XAML
is all about UI, whereas WF XAML is all about business processes. So in order to
distinguish both a new extension XOML has been introduced which is in fact
eXtensible Object Markup Language (you may call it as workflow markup). And if
we really look into XAML then it is just a new format for serializing WPF .NET
types into XML. There is no syntactical difference between the XAML and XOML, only
the semantics differ.
After we have the workflow file
added in our solution, we can simply open it up with an XML Editor or the
default Workflow Designer. In the workflow designer, drag and
drop the Code Activity to the design surface of our sequential workflow.
Fig. 05
Well you can see a red exclamation mark in the above figure. The smart tag
will tell you that the property ExecuteCode has not been set i.e. you need to
add a handler against your activity.
Go to properties, under the
Events section double click the ExecuteCode property, and there you have it. A
stub generated for you right in you code beside the file. Here is what your code
will now look like:
namespace _1SequentialWF
{
public partial class Workflow1 : SequentialWorkflowActivity
{
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
}
}
}
Just add your code that you want to execute here e.g. we have added a simple
display message that will print "Hello Workflow!" in the console output window.
Fig. 06
You can also set a breakpoint on your Code Activity. To get an understanding
of what's actually happening behind the scenes let's have a look at the
Program.cs file and see what code the designer has generated for us.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
namespace _1SequentialWF
{
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(_1SequentialWF.Workflow1));
instance.Start();
waitHandle.WaitOne();
}
}
}
}
If we write pseudo code of the above code it will look like this:
- Main method
begins.
- A new
instance of the WorkflowRutime class is created.
- Handlers are
added.
- An instance
of the WorkflowInstance class is created.
- The
particular workflow is assigned to the instance.
- The
workflow class constructor is executed and all properties of all activities
within the workflow are set.
- Instance is
executed.
- The main
method waits for all the activities in the workflow to finish execution.
- Each
activity is now processed e.g., in our case it is the ExecuteCode hander of our
Code Activity that is executed.
- Main method
completes
Interesting isn't it. You have just added a simple activity and defined a simple
task for that activity and the rest is all handled for you automatically.
Passing data into the workflow
One of the many workflows that
needs to be implemented might need to have values passed into it e.g. userID of
the logged in user etc. A workflow can accept input
parameters or can provide output parameters which are defined, within the
workflow as properties.
Another way of passing data into
the workflows is through events. With events, workflow authors add an activity
that receives an event and the data associated with it.
Let us modify our previous code
and introduce properties in it. Here we will host our workflow application in a
Windows Form application by adding a reference to the System.Windows.Forms
assembly.
Fig. 07
namespace _1SequentialWF
{
public partial class Workflow1 : SequentialWorkflowActivity
{
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Hello Workflow! " + FirstName + " " + LastName);
System.Windows.Forms.MessageBox.Show("Hello Workflow! " + FirstName +
" " + LastName);
}
private string myFirstName;
public string FirstName
{
get { return myFirstName; }
set { myFirstName = value; }
}
private string myLastName;
public string LastName
{
get { return myLastName; }
set { myLastName = value; }
}
}
}
Now we are ready to launch our workflow application from a windows
application. Let's do that by adding a new Windows application to our solution.
Fig. 08
Now we will set our Windows application as our StartUp project and will add
the reference of our workflow application.
Note: the
output mode of our workflow application must be set to Class Library before
adding the reference, and must be then compiled to build the output dll.
Fig. 09
Now after adding the reference to our workflow project,
the next step is to add reference to the WF system assemblies. Let's do that as
well!
Fig. 10
After this we will design our form by dropping two labels,
two text boxes and a button on our form so that our form looks like:
Fig. 11
Here is the associated code behind the form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
namespace WindowsApplicationHost
{
public partial class Form1 : Form
{
private WorkflowRuntime wr;
public Form1()
{
InitializeComponent();
}
private void btnBeginWorkflow_Click(object sender, EventArgs e)
{
if (wr == null)
{
wr = new WorkflowRuntime();
wr.StartRuntime();
}
Dictionary<string,> parameters = new Dictionary<string,>();
parameters.Add("FirstName", txtFirstName.Text);
parameters.Add("LastName", txtLastName.Text);
WorkflowInstance instance = wr.CreateWorkflow(
typeof(_1SequentialWF.Workflow1), parameters);
instance.Start();
}
private void btnCloseWorkflow_Click(object sender, EventArgs e)
{
if (wr != null)
{
if (wr.IsStarted)
{
wr.StopRuntime();
MessageBox.Show("Workflow successfully stopped");
}
else
{
MessageBox.Show("Workflow not started yet");
}
}
}
}
}</string,></string,>
We have simply added the references to WF namespaces. In our main application
we have created an instance of WorkflowRuntime and used a simple
Dictionary object to hold input from the user which we have passed to the our
workflow.
Following is the output of our application:
Fig. 12
Fig. 13
This way we have successfully hosted our workflow application in a Windows
form application and also passed values to our workflow.
In the coming
articles I will be describing in detail, how we can attach various activities,
declare rule-based workflows and also a detailed insight into the State Machine
workflows and Activity Library and then the rest of the components of Microsoft
.NET Framework 3.0
Happy Coding~