Get Ready for Windows Workflow Foundation

During its long and storied history, Microsoft has had a number of forays into the world of workflow. The company has built workflow solutions for Microsoft Exchange, another in Dynamics CRM, and others within BizTalk, SharePoint, and Content Management Server. However, each of these was generally more for utility use, or it was fragmented, incomplete, or considered more of a false start. Often, third-party products were required to provide true workflow within Microsoft-based solutions.

To bring workflow to the masses and allow for long-running workflows in applications and servers, Microsoft will introduce the much-anticipated Windows Workflow Foundation (WinWF) as part of the .NET Framework 3. WinWF provides a workflow engine, a programming model, and a set of tools for rapidly building workflow-enabled solutions. It offers a single workflow technology for Windows that serves as a base for Microsoft products as well as ISV and customer solutions. Microsoft itself will be utilizing WinWF in the near term to workflow-enable several Microsoft products such as Microsoft Office 2007 and Microsoft BizTalk Server.

While providing only a framework to build on—not an application or server, WinWF is intended as a common platform for Microsoft, ISVs, and others (including you) to build workflow into applications and workflow-enabled servers. In fact, many workflow vendors are rebuilding their products to sit on top of WinWF and provide additional capability.

This article explores WinWF and describes how to build a sequential workflow, which is one of the several workflow types supported by the Microsoft .NET Framework 3.0 and Visual Studio 2005. To build the examples, you need the following components:

  • .NET Framework 3.0 Runtime Components
  • Visual Studio 2005 Extensions for .NET Framework 3.0 (Windows Workflow Foundation)

I personally downloaded them and set up a .NET Framework 3.0 Virtual PC environment, which I've found to be a good practice for trying out new things without risk of messing up my current environment.

Workflow Basics

Within WinWF, Microsoft defines a workflow as a set of one or more activities that coordinate people and/or software. At their heart, workflows are a set of activities that run within a host process of any application or server. They are a map of activities with a control flow as well as support for dynamic change. An application hosts the workflow, runtime services within .NET support persistence for long-running transactions, and the workflow runtime controls instances of workflows.

There are two different workflow scenarios based on the participant types. In human workflow, participants are people and roles. A person must be involved in the process in some form, and the process typically flows dynamically, needs to be flexible, and likely involves documents of some type. The alternative is system workflow, where the participants are applications and services. It is more of a structured flow of data, fairly prescriptive from system to system, and likely transactional in nature. In the past, Microsoft provided system-to-system workflow through Microsoft BizTalk, but didn't have a good answer for human workflow. WinWF will serve as the core for human and system workflow.

Two different styles of workflow also are available: sequential workflow and state machine workflow. The sequential workflow is just as the name implies, it involves a prescribed processing order that relates closely to a flowchart model. A state machine workflow is more reactive. It is event driven, with the external events driving the processing order. In state machine workflow, you can skip or rework steps triggered based on various events within the workflow.

Activity Basics

Activities are the building blocks of workflows. They represent the basic steps within a workflow and make up the individual units of execution. Activities allow for re-use and composition of a solution by assembling together existing activities into a set of activities. Activities can even be a composition of one or more other activities.

A base activity library provides out-of-the-box activities, but you also can write custom activities or obtain them from third parties. The following are some of the library's common activities that you can use to arrange a workflow:

  • Code: Executes the associated code
  • Delay: Delays execution of the workflow for a specified duration
  • IfElse: Executes different activities based on the condition
  • InvokeWebService: Invokes a Web service call from within a workflow
  • Suspend: Suspends execution of the workflow
  • Terminate: Terminates execution of the workflow
  • While: Executes associated activities as long as the condition is true, where the condition can be based on declarative rules set at design time or based on code

As you can see, the activities offer some powerful capabilities by default. Activities can support transactions and sequential control, along with being rules driven. The declarative rules support within activities is very powerful becayse it allows you to alter or change the logic without recompiling code.

Authoring Workflows

The WinWF engine is designed to allow declarative and programmatic authoring of workflows. Declarative definition is when XML markup is used to define the workflow structure, logic, and data and the workflow compiler turns it into physical objects. This is significant because it will allow for non-developers to be workflow authors through tools such as the Microsoft Office SharePoint Designer 2007, which allows the user to draw a workflow and then runs it through the compiler automatically.

When authoring workflows in Visual Studio 2005, you have the options of keeping the definition and the code in the same file or having code separation with the workflow definition expressed as XAML and the user code contained in a separate code file. I traditionally prefer to use the code-behind concept and stick with it.

Sequential Workflow

As previously mentioned, a sequential workflow involves a prescribed processing order that relates closely to a flowchart model. For demonstration, this article creates a sequential workflow that includes a single code activity that writes the phrase "Hello World!" to a Windows console. Follow along and you will learn how to set up a workflow and practice debugging it.

Building a sequential workflow

Take the following steps to create a sequential workflow within Visual Studio 2005:

  1. Create a new project. This example uses C# -> Workflow -> Sequential Workflow Console Application as the project type.
  2. When you create the workflow project, it will use the workflow definition and the code in the same file by default. I deleted it and added a new item, Sequential Workflow (with code separation), and named it HelloWorkflow.xoml.
  3. In the Toolbox, you will find a Windows Workflow group. Drag a Code activity onto the Sequential Workflow designer. I named my activity helloActivity.
  4. A Smart Tag on the control will indicate that the property ExecuteCode is not set. The ExecuteCode property specifies the name of the code method that will be invoked by the runtime. Set the property to be the name of your activity followed by _EventHandler. In my case, I used helloActivity_EventHandler.
  5. Add Console.WriteLine("Hello World!"); to the event handler that was added.
  6. Set a break point in the code behind. You should also set a breakpoint in the workflow designer.
  7. Build and execute your project in debug mode. You should see the first break point stop in the designer prior to the execution of the code activity.

Figure 1 shows a screenshot of the workflow designer with the single activity.

Figure 1: Workflow Designer with Single Activity

Here is a copy of the code that was created in my project:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;

namespace HelloWorldWorkflow
{
   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(HelloWorldWorkflow.HelloWorkflow));
            instance.Start();

            waitHandle.WaitOne();
         }
      }
   }
}

You should see a Program.cs that contains the main execution point for the console application and autogenerated code.

Here is the code from the HelloWorld.xoml.cs code behind file:

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;

namespace HelloWorldWorkflow
{
   public partial class HelloWorkflow : SequentialWorkflowActivity
   {
      private void helloActivity_EventHandler(object sender,
                                              EventArgs e)
      {
         Console.WriteLine("Hello World!");
      }
   }
}

This is a fairly simple example that gives you an idea of how to build a sequential workflow. You could expand it to use the IfElse activity to display the "Hello World!" text based on various languages, or you could further explore other activities.

Get Ready for Windows Workflow Foundation

Building a sequential workflow with parameters

The example in this section adds some logic to the sequential workflow to make a decision based on a particular property value. Take the following steps to modify the prior example within Visual Studio 2005:

  1. Add a property of bool type to the code-behind file. Have the default value for the property set to false. I chose to name the property IsTrue.
  2. Drag an IfElse activity to the top of the workflow designer.
  3. Drag the prior helloActivity into the left side of the IfElse branch.
  4. Add a terminate activity to the right branch of the IfElse activity.
  5. Use the smart tag on the ifElseBranchActivity1 to set a declarative rule condition. This will allow you to use the designer to set the logic condition to use. The expression you should use is this.IsTrue == true, which will base the condition on the IsTrue property of the sequential workflow.
  6. Set a breakpoint in the workflow designer on the IfElse activity.
  7. Build and execute your project in debug mode. You'll notice that the "Hello World!" will be skipped because your condition is set to false by default.

Figure 2 shows a screenshot of the workflow designer with the modifications.

[Figure2.JPG]

Figure 2: Workflow Designer with Modifications

Here is a modified version of the Program.cs class:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;

namespace HelloWorldWorkflow
{
   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();
            };

            // Create a dictionary to hold workflow parameter values
            Dictionary<string, object> parameters =
               new Dictionary<string, object>();
            parameters.Add("IsTrue", true);

            // Pass parameter values to the workflow as it is created
            WorkflowInstance instance = workflowRuntime.CreateWorkflow(
               typeof(HelloWorldWorkflow.HelloWorkflow), parameters);
            instance.Start();

            waitHandle.WaitOne();
         }
      }
   }
}

I added some specific code to allow for parameters to be passed in to the HelloWorkflow. I did this by creating an instance of the Dictionary<string, object> generic class and assigning a key and value pair to it for the IsTrue property value. You would add additional parameters to the instance of the Dictionary class for any other parameters you chose to add to your workflow. By toggling the value back and forth in code from true and false, the workflow will display or not display "Hello World!" accordingly. This demonstrates a programmatic way to control the display. You could just as easily read the value from a configuration file, seek input from another source such as a web service, or take input from a user interface.

Here is the code from the HelloWorld.xoml.cs code-behind file with the additional property:

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;

namespace HelloWorldWorkflow
{
   public partial class HelloWorkflow : SequentialWorkflowActivity
   {
      private bool isTrue = false;
      public bool IsTrue
      {
         get { return this.isTrue; }
         set { this.isTrue = value; }
      }

      private void helloActivity_EventHandler(object sender,
                                              EventArgs e)
      {
         Console.WriteLine("Hello World!");
      }
   }
}

WinWF and Sequential Workflow

Just like that, you've gotten a WinWF background, workflow basics, activity basics, authoring workflows, and some sequential workflow examples. Hopefully, you found the topic intriguing and are ready to start exploring WinWF within your applications.

Future Columns

The topic of the next column is yet to be determined. It likely will be either state machine workflow, building custom activities, or building a rules-based workflow using WinWF. However, if you have something in particular that you would like to see explained here, contact me at mstrawmyer@crowechizek.com.



About the Author

Mark Strawmyer

Mark Strawmyer is a Senior Architect of .NET applications for large and mid-size organizations. He specializes in architecture, design and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C# for the fifth year in a row. You can reach Mark at mark.strawmyer@crowehorwath.com.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: May 6, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT While you likely have very good reasons for remaining on WinXP after end of support -- an estimated 20-30% of worldwide devices still are -- the bottom line is your security risk is now significant. In the absence of security patches, attackers will certainly turn their attention to this new opportunity. Join Lumension Vice President Paul Zimski in this one-hour webcast to discuss risk and, more importantly, 5 pragmatic risk mitigation techniques …

  • With JRebel, developers get to see their code changes immediately, fine-tune their code with incremental changes, debug, explore and deploy their code with ease (both locally and remotely), and ultimately spend more time coding instead of waiting for the dreaded application redeploy to finish. Every time a developer tests a code change it takes minutes to build and deploy the application. JRebel keeps the app server running at all times, so testing is instantaneous and interactive.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds