Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Introduction to WF (Part01)

4.89/5 (61 votes)
19 Apr 2007CPOL15 min read 1   1.9K  
A series of articles on Microsoft NetFx3. Starting initial writings with WF.

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:

  1. Sequential
  2. 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:

  1. Declarative XAML.
  2. Imperative code using any .NET targeted language.
  3. 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:

  1. Scheduling (schedules the execution of activities within a workflow)
  2. State Management (allows the state of the workflow to be persisted instead of storing it in some other mechanism like database)
  3. 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.

Screenshot - image002.jpg

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:

Screenshot - image004.jpg

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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. Event Driven Activity: This is a flow activity that contains other activities that are to be executed when an event occurs.
  6. 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.
  7. 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.
  8. 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.
  9. Listen Activity: This activity is a composite activity. It requires a minimum of two event driven activities.
  10. 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.
  11. 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.
  12. 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.
  13. 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.
  14. Set State Activity: This is a flow activity that is used to specify changeover to a new state within a state machine workflow.
  15. 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.
  16. 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.
  17. 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.
  18. 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.
  19. 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.
  20. Transaction Scope Activity: This activity offers transaction support. All activities that make up a transaction are placed in this activity.
  21. 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.

Screenshot - image010.jpg

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.
Screenshot 

- image011.png
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.

Screenshot - image014.jpg

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.

Screenshot - image016.jpg

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:

C#
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.

Screenshot - image018.jpg

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.

C#
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:

  1. Main method begins.
  2. A new instance of the WorkflowRutime class is created.
  3. Handlers are added.
  4. An instance of the WorkflowInstance class is created.
  5. The particular workflow is assigned to the instance.
    1. The workflow class constructor is executed and all properties of all activities within the workflow are set.
  6. Instance is executed.
  7. The main method waits for all the activities in the workflow to finish execution.
  8. Each activity is now processed e.g., in our case it is the ExecuteCode hander of our Code Activity that is executed.
  9. 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.

Screenshot - image020.jpg

Fig. 07

C#
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.

Screenshot - image022.jpg

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.

Screenshot - image024.jpg

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!

Screenshot - image026.jpg

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:

Screenshot - image028.jpg

Fig. 11

Here is the associated code behind the form:

C#
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:

Screenshot - image029.png

Fig. 12

Screenshot - image031.png

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~

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)