Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Windows Workflow Foundation - State Machine Workflow Example

3.07/5 (16 votes)
20 Sep 2007CPOL5 min read 2   947  
An article describing how to program with Windows Workflow Foundation which comes with .NET Framework 3.0

Introduction

This article describes how to create and run a State Machine Workflow in Windows Workflow Foundation (formerly WWF, or just WF) which comes bundled with .NET Framework 3.0 and above.

Before we get started, if you are new to WF and .NET Framework 3.0, I think you'd better take a look at some articles about WF. Here are some useful links:

Background

In order to create WF applications, you need to install some required packages/tools.

These are:

  1. .NET Framework 3.0 Runtime
  2. Visual Studio 2005 Professional Edition
  3. Windows Workflow Foundation extensions for Visual Studio 2005
  4. Windows Communication Foundation (WCF,formerly Indigo) & Windows Presentation Foundation (WPF,formerly Avalon)

The fourth one is optional in fact. However, there may be some troubles and you may get some weird error if you don't have WCF and WPF installed on your development computer. So, I suggest you have WCF and WPF installed too.

Now, I want to demonstrate a daily life example. Assume that you want to lock something (A file, a safe, a door,...etc.). This locker has exactly 2 different states: LOCKED and UNLOCKED. And you change its state by opening and closing. In our application, we call some methods to change workflows state; from/to LOCKED to/from UNLOCKED.

Using the Code

Let's dig in the code.

First we open .NET Visual Studio 2005. In the Start Page window, click Project from Create row. In the New Project window, extend Visual C# node, then select Workflow. There are many applications but we will create a state machine application so we select State Machine Workflow Library and name it FirstStateMachineWorkflow. Then click OK.

Screenshot - 1.jpg

After creating the application, your designer window should look like this:

Screenshot - 2.jpg

NOTE: If you can't see Workflow1.cs[Design] or if there is something wrong with the steps above, go check the requirements. Probably you missed some of them or they are not installed properly.

Now, we need an interface to declare the events. Right click the project -> Add -> New Item -> Select Interface and name it ILocker.cs. Write the code below to the interface.

C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.Activities;

namespace FirstStateMachineWorkflow
{
    [ExternalDataExchange]
    public interface ILocker
    {
        event EventHandler<ExternalDataEventArgs> Lock;
        event EventHandler<ExternalDataEventArgs> Unlock;
    }
}

Lock and Unlock are our events which make the workflow change its state. Now we need a class implementing this interface and having the methods to fire the events. Right click the project -> Add -> New Item -> Select Class and name it Locker.cs. Write the code given below to the class:

C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.Activities;

namespace FirstStateMachineWorkflow
{
    [Serializable]
    public class Locker : ILocker
    {
        public event EventHandler<ExternalDataEventArgs> Lock;
        public event EventHandler<ExternalDataEventArgs> Unlock;

        public bool lockerState = false;

        public bool LockIt(Guid InstanceID)
        {
            if (this.Lock != null)
            {
                this.Lock(this,
                    new System.Workflow.Activities.ExternalDataEventArgs(InstanceID));
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool UnlockIt(Guid InstanceID)
        {
            if (this.Unlock != null)
            {
                this.Unlock(this,
                    new System.Workflow.Activities.ExternalDataEventArgs(InstanceID));
                return false;
            }
            else
            {
                return true;
            }
        }
    }
}

As you see Locker class uses events to change the workflows state. These two methods (LockIt and UnlockIt) are going to be used by the host application.

Now, we go back to our workflow designer window. Open Workflow1.cs[Designer]. Click the state and in the properties window, change its name as Unlocked. On the right-hand side tool box, drag and drop EventDrivenActivity on the state. Change its name as LockEvent and double-click. This will open a new design window. On the toolbox, drag and drop HandleExternalEventActivity and change its name to HandleLockEvent. This will help us to handle the event fired by the host application. While HandleLockEvent is selected, in the properties window, click the InterfaceType property. A new window will open, there, select ILocker. This is needed to define which events are handled by which event handler. Now, above in the properties window, select Lock in the EventName combo-box. So far, we made the Lock event to be handled by this handler. But after handling, we want to write a message to the console stating which event is handled. To do this, drag and drop a CodeActivity from toolbox, name it LockedCode, double click it. You will go to Code View. There in the LockedCode_ExecuteCode method, write the code below:

C#
private void WriteState_ExecuteCode(object sender, EventArgs e)
{
    Console.WriteLine("Locked!!!");
} 

So, we handled the event, wrote the message, what next? Now we must do something to change the current state. From toolbox drag and drop a new StateActivity to Workflow1.cs[Design] and name it as Locked. Now in HandleLockedEvent view, drag and drop SetStateActivity under code activity. Name it as SetLocked and in the properties window, set TargetStateName as Locked.

Do the same steps for Locked state reversed and properly. Drag drop HandleUnlockEvent, add UnlockedCode and SetUnlocked to Unlocked.

After all these changes, your Workflow1.cs[Designer] should look like this :

Screenshot - 4.jpg

Now it is time to add a host application to the solution.

NOTE : Remember, Windows Workflows (be it State Machine or Sequential Workflow) cannot run by themselves. They need an external host application. The application may be a Windows application, Console Application or Web Application (ASP.NET).

Right click solution -> Add -> New Project. In the New Project window, select Visual C# and select Console Application , name it Test.

After creating the console application, right click on the console application and select Set As StartUp Project. We must add reference to use workflow methods. To do that, right click References -> Add Reference -> In .NET tab, select System.Workflow.Activities, System.Workflow.Runtime, System.Workflow.ComponentModel.

Screenshot - 6.jpg

We need FirstStateMachineWorkflow reference also. References -> Add Reference -> In Projects tab, select FirstStateMachineWorkflow and click OK.

Screenshot - 5.jpg

In Program.cs, write the code given below to run the workflow:

C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow;
using System.Workflow.Activities;
using System.Workflow.Runtime;
using FirstStateMachineWorkflow;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            WorkflowRuntime workflowruntime = new WorkflowRuntime();
            Locker locker = new Locker();
            Guid locker_ID = Guid.NewGuid();
            Dictionary<string,object> Params = new Dictionary<string,object>();
            ExternalDataExchangeService ExDateExchService =
                    new ExternalDataExchangeService();
            workflowruntime.AddService(ExDateExchService);
            ExDateExchService.AddService(locker);
            WorkflowInstance wfinstance = workflowruntime.CreateWorkflow(
                typeof(Workflow1) , Params , locker_ID );
            wfinstance.Start();

            locker.LockIt(locker_ID);

            Console.ReadLine();

            locker.UnlockIt(locker_ID);

            Console.ReadLine();
        }
    }
}

Here, WorkflowRuntime object is used to configure workflow properties, Locker is our class implementing interface. Dictionary is to pass parameters to workflow. However, we don't have any parameters in our example.

C#
WorkflowInstance wfinstance = workflowruntime.CreateWorkflow(
      typeof(Workflow1) , Params , locker_ID );
wfinstance.Start();

WorkflowInstance is used to create an instance of our Workflow1 workflow and then it is started with the wfinstance.Start method.

After running this application, you should get this console window:

Screenshot - 7.jpg

Points of Interest

As I mentioned before, WF itself is not enough to create WF applications. You may have WCF and WPF installed as well as WF.

And to summarize the steps again:

  1. Create a workflow statemachine application.
  2. Write an Interface for transitions between states (Write events).
  3. Write the [Serializable] class implementing the interface events and calling them
    in functions.
  4. Create a host application which uses the class and starts workflow.

History

20th September, 2007: First release

License

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