Introduction

This article contains the world’s most trivial and useless Windows Workflow Foundation (WF) application, as well as some background on WF itself. The purpose of this software freak show is to expose a WF newcomer to the basics of how to get started with this exciting new part of .NET 3.0. It does not get into any sophisticated scenarios and certainly does not contain any WF best practices. It just shows you how to put together a minimal WF app. If you have more realistic needs and requirements, you might use this code as a starting place for real development.

I will admit right here (New York City) and now (November 2006) that I am by no means a WF expert. I’m just really excited about WF, and have been reading about it and playing around with it in my free time. This article was written purely out of excitement for the technology, so I hope that excitement shines through and helps get you excited too.

The application shown in this article is a mutation of the demo app used in the beginning of the excellent book “Essential Windows Workflow Foundation” by Dharma Shukla and Bob Schmidt. I highly recommend that book if you want to get serious about learning WF. You might also want to check out this article on MSDN, by Don Box and Dharma Shukla.

WTF is WF?

Before we get into building a WF application, let’s take a moment to grasp the general ideas behind WF. WF stands for Windows Workflow Foundation. It is a subsystem of the .NET Framework 3.0 which provides a runtime for creating and executing workflow-based applications. That’s nice marketing babble, but what exactly does that mean? Good question…

From a very high-level perspective, WF allows you to create programs that can be persisted to a backing store when they are inactive and then resumed when necessary. You can declare the overall program flow in an XML-based language known as eXtensible Application Markup Language (XAML) and load/execute your XAML workflow at runtime. Expressing your application’s general logic flow in a markup language simplifies the development process greatly, especially because it opens new possibilities for the use of graphical design tools in creating software.

Why Would I Use WF?

Many applications are reactive by nature. They sit around for an indefinite period of time waiting for something to happen (perhaps a file to be created in a certain directory). When that external stimulus arrives the application gets busy processing the incoming data. The problem with this common scenario is that performance and scalability are greatly affected by the fact that while an application is waiting for external input, it consumes processing time from whatever thread it runs on.

WF provides a solution to that problem. Since a workflow in WF is represented as a tree of objects, and those objects support being serialized/deserialized, WF workflows have built-in support for being saved to and loaded from a database. I don’t mean that just the data manipulated by the application is saved; I mean that the “program” itself is saved.

The state of the application is effectively “frozen” and put into a cryogenic freezer, so to speak. When it comes time to resume the workflow processing (i.e. the external stimulus arrives) the “frozen” workflow is thawed out and it continues executing as normal. Keep in mind that the workflow could be resumed on a different computer, a thousand miles away from where it was frozen, fifteen months later. This brings tremendous gains in terms of performance and scalability, because the workflow is not bound to a specific thread, process, or even computer.

That’s all of the introductory material I’m going to provide on WF. I didn’t explain nearly all of what WF is all about. If you are interested in a more thorough and circumspect explanation of WF, I recommend you read the book mentioned previously (“Essential Windows Workflow Foundation”). Now let’s play with some WF code!

The World’s Stupidest WF Application

The application I’m going to present to you here asks the user for his/her name, waits for the user to type it in, and then prints “Hello, UserName!” to the console. Obviously this application is only of interest because it uses Windows Workflow Foundation to perform its magic. I tried to keep the use of WF as simple and minimal as possible, just so that it’s easy to see how one goes about setting up an application which uses WF.

There are two assemblies involved in this application:

FirstWFLibrary.DLL – This assembly contains the custom WF Activities which are used to perform the tasks of printing output to the console, and getting the user’s name.

FirstWFApp.EXE – This assembly is a console app which loads the WF WorkflowRuntime and puts the Activities in FirstWFLibrary to use.

Each of the two assemblies contains two pieces of the puzzle:

FirstWFLibrary.DLL

Custom Activities – The fundamental unit of work in a WF workflow is an 'activity.' All custom activities in a WF application derive from the Activity base class and override its protected Execute method to provide their own execution logic.

Namespace Mapping – In order to be able to use our custom Activities in XAML we need to provide a way to tell the XAML parser the namespace(s) in which those classes exist. This is accomplished by applying an attribute to the assembly, as we will see later.

FirstWFApp.EXE

Workflow Declaration – In this application the workflow required for reading the user’s name and displaying it back to him/her is expressed in XAML. The XAML file in this assembly uses the custom Activities declared in the FirstWFLibrary assembly. Note, it is not required that workflows are declared in XAML. It is entirely possible to declare them in other formats, such as C# code. I chose to express the workflow in XAML for this application because it’s more fun that way.

Workflow Runtime Host – The last piece of the puzzle is a class which loads the WF runtime, configures it, and then tells it to start running. The EntryPoint class in this application takes care of that job.

The rest of this article examines each part of the application listed above.

Custom Activities

As mentioned previously, this demo application has three tasks to perform. First it must display a message in the console window which asks the user for his/her name. Then it must wait for the user to enter their name and press Enter. Finally it displays another message to the user, which includes their name in it.

Each of those tasks is represented as a separate Activity-derived class. Instances of those classes will perform the actual work necessary to make the program execute. First let’s see how the initial prompt is displayed to the console.

This class is a perfect demonstration of how to create an activity which can be included in a WF workflow. It inherits from the System.Workflow.ComponentModel.Activity class and overrides the Execute method to provide custom activity execution logic. Since this activity is logically complete after it writes a message to the console, it returns ActivityExecutionStatus.Closed to inform the WF runtime that it is done.

You might be wondering why an activity would return from the Execute method if it was not done executing. Remember earlier on I mentioned that WF workflows can be “passivated” and stored in a database until it needs to continue executing? Well, an activity’s Execute method will return ActivityExecutionStatus.Executing if it cannot complete until external input eventually arrives.

In fact, the next step of The World’s Stupidest WF Application requires an indefinite period of time to elapse before it can continue processing. It might take the user three seconds or three days to type in his/her name. During that time the workflow will have nothing to process. If this was a less stupid WF application, we might decide to passivate the workflow until the user name finally arrives, at which point we would resume the workflow and let it continue. We’re not doing that here, but this next activity shows how to set up a “bookmark” so that the WF runtime can inform the activity when input has arrived.

In the ReadConsoleLine’s Execute method a “bookmark” is established and the method immediately returns control back to the WF runtime. However, it returns ‘Executing’ to let the WF runtime know that it should not go on processing any other activities yet. When the user input finally arrives, the ReadConsoleLine’s ProcessQueueItemAvailable and CloseActivity event handling methods will be invoked. The first of those methods stores the user’s name in a private variable. The other method cleans up and closes the activity, so that the WF runtime can continue processing other activities.

The last activity is responsible for printing out a greeting to the user, with his/her name in it. This activity has a dependency property called UserName. As we will see later, this property is bound to the input value received by the ReadConsoleLine activity. The data binding is established in the XAML declaration of these objects. We’ll get to that soon, but now let’s see the GreetUser activity.

Namespace Mapping

In order to use our custom activities in XAML we need to provide a way for the XAML parser to know what CLR namespace those classes reside in. Since XAML is an XML-language, we need to provide a way of associating the CLR namespace with an arbitrary XML namespace (basically, a URI). This can be done in any code file in the project, but I created an AssemblyInfo.cs just for the sake of tradition. Here’s the contents of that file:

using System.Workflow.ComponentModel.Serialization;
// This attribute makes it possible to use our custom activities in XAML.
[assembly: XmlnsDefinition( "http://FirstWFLibrary", "FirstWFLibrary" )]

Workflow Declaration

Now that we have the custom activities needed to perform our program logic, and their namespace is mapped, we can create instances of those types. In this demo we will create them in XAML. Think of XAML as just an all-purpose object instantiation markup language. It allows you to configure objects and express the hierarchical relationships between them very easily.

The root activity in the workflow is a SequenceActivity object, which is a class provided in the WF framework. It is a CompositeActivity-derived class which executes its child activities in the order they are declared, only executing one child activity after the previous child activity is complete.

The root activity contains the XML namespace mappings. The default XML namespace is mapped to the URI specified in the XmlnsDefinition attribute in the previous section of the article. That allows us to refer to our custom activity types without any namespace prefix.

Another point of interest is the relationship between the ReadConsoleLine and the GreetUser activities. The UserName property of the latter is bound to the InputText property of the former. This binding allows the text typed into the console to be transferred from one activity to another. For a property to be the target of a binding, it must be a 'dependency property.' As we saw in the 'Custom Activities' section, there is a little more code involved with creating a dependency property than just a normal property, but dependency properties can be used in ways that normal properties cannot. You can read about those differences in the SDK, if you care.

Workflow Runtime Host

You can host the WF runtime in a variety of ways, but this demo just uses a plain vanilla console application. There are a few steps you must follow to get the WF runtime up and running in your AppDomain. The following method is where The World’s Stupidest WF Application hosts the WF runtime (this method is, of course, in a class):

publicstaticvoid Main()
{
// Create an instance of WorkflowRuntime, which will execute and coordinate
// all of our workflow activities.
using( WorkflowRuntime workflowRuntime = new WorkflowRuntime() )
{
// Tell the Workflow runtime where to find our custom activity types.
TypeProvider typeProvider = new TypeProvider( workflowRuntime );
typeProvider.AddAssemblyReference( "FirstWFLibrary.dll" );
workflowRuntime.AddService( typeProvider );
// Activate the Workflow runtime.
workflowRuntime.StartRuntime();
// Load the XAML file which contains the declaration of our simple workflow
// and create an instance of it. Once it is loaded, the workflow is started
// so that the activities in it will execute.
WorkflowInstance workflowInstance;
using( XmlTextReader xmlReader =
new XmlTextReader( @"..\..\HelloUserWorkflow.xaml" ) )
{
workflowInstance = workflowRuntime.CreateWorkflow( xmlReader );
workflowInstance.Start();
}
// The ReadConsoleLine activity uses a "bookmark" to indicate that it must
// wait for external input before it can complete. In this case, the
// external input is the user's name typed into the console window.
string userName = Console.ReadLine();
workflowInstance.EnqueueItem( "getUserName", userName, null, null );
// Pause here so that the workflow can display the greeting.
Console.ReadLine();
// Tear down all of the Workflow services and runtime.
// (This is probably redundant since the 'runtime' object is in
// a using block).
workflowRuntime.StopRuntime();
}
}

I’m not going to explain that method line by line, because it is commented well enough. The one point of interest I will mention is that once the WorkflowInstance starts, the method then calls Console.ReadLine to get the user’s name. Once the name is retrieved, it is put onto the “getUserName” workflow queue, which was created by and for the ReadConsoleLine activity. This is an example of external input being provided to the workflow, causing it to resume processing. Once the user’s name is put onto the workflow queue, the ReadConsoleLine activity will have its callback methods invoked so that it can finish executing.

Conclusion

This article showed how to create an application which uses Windows Workflow Foundation. Hopefully it left you feeling like The World’s Stupidest WF Application deserves its name, but also that you understand the fundamentals of WF and how to use it in an application.

As I mentioned before, this application does not at all need to use the powers of WF, but it does convey the basic concepts involved. It shows how WF workflows are a tree of activities, how those activities can use the concept of “bookmarks” to indicate where processing should continue after external stimulus occurs, how a workflow can be declared in XAML, and how to host the WF workflow runtime. Along the way I mentioned that WF workflows can be passivated and resumed, which provides a powerful means of improving an application’s scalability and performance.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Please I am developing a web based library circulation system.
I want to use windows workflow sequential for checking out books
the parton id and book id can be an input parameter how can I read from and update the database from within the windows workflow
shall i use a seqential workflow library or web servic

I am using visual studio 2005

Please where can i find information about sequential workflow and asp.net allowing the workflow to read and update the library circulation database

A nice article introducing workflow. However, can I add a word of caution to any CPians about MS WF.

I started to look at workflow last year when the first details started to appear, and then again in March/April when the betas came out. I'm a big fan of workflow in the general sense, but after playing with WF for three months I gave up.

My warning is this: WF (workflow) is complex. VERY VERY complex.

Because of the very complex features (like suspending, multi-threading, dependency properties etc.) the programming model and work involved to understand it all is immensely complex.

Unless you are very proficient in .NET I would suggest that you steer clear. The simple examples usually hide the real complexity of workflow that lies just ahead when trying to do something simple.

An example of this is the work involved in sending a simple message to a running workflow instance from an application (either asp or winforms). See this article (point 3) which explains the work involved.

When you think that interaction between applications and workflow (rather that wholly self-contained workflow) is the key then you begin to see how much work is (a) involved in understanding all this and (b) in actually coding anything.

I also found that simple things you might expect have no direct support, and if you try subclassing WF you are entering the realm of the super-complex.

For example, you might want a workflow process to be assigned to a human at some stages of it's lifetime. The helpdesk examples on WF would be a case in point. WF leaves this to the developer, as there are almost an infinite number of ways to do this. Bear in mind there is no 'query' function for workflows that can say

'select * from workflowinstances where [someproperty]=[somevalue]'

So the logical approach was to build a database table to track workflows I had created. I wanted to subclass the StateActivity to then assign workflows and add code that would update the database to say who the task was assigned to. My god it was complicated and eventually I gave up. The subclass code was not able to see the workflow instance dependency properties!

Just my two cents. Many of the examples I have seen on the internet so far regarding WF are trying to use a trying to use a tank to kill an ant. WF is an application level concept - Microsoft has taken it a step further and enshrined it in a framework - giving developers a conceptual (and in some ways tangible) way of building applications without needing to recreate the framework.

I think there are too many situations where many of us developers (yes myself included) get caught up in the hype behind a technology without giving much thought to the suitability of the technology for a the task.

Bear this in mind with WF - though it has a high learning curve, it should not deter you if the task you have in mind is suitable for it - in fact the time you will put in can be more than worth the effort.

Just my two cents. Many of the examples I have seen on the internet so far regarding WF are trying to use a trying to use a tank to kill an ant. WF is an application level concept - Microsoft has taken it a step further and enshrined it in a framework - giving developers a conceptual (and in some ways tangible) way of building applications without needing to recreate the framework.

I think there are too many situations where many of us developers (yes myself included) get caught up in the hype behind a technology without giving much thought to the suitability of the technology for a the task.

Bear this in mind with WF - though it has a high learning curve, it should not deter you if the task you have in mind is suitable for it - in fact the time you will put in can be more than worth the effort.

I think Microsoft's version of workflow is very hard to use.
After using Oracle's BPEL(workflow), I found out it's way easier to use. You do the design and deploy to the application server, don't need to CODE. Microsoft needs an application server that can do the same.

I think .. Workflow can be run in appdomain, instead of putting all your dll/code in some sort of DATABASE, and database running ur code!

"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David CrowNever mind - my own stupidity is the source of every "problem" - Mixture

At the beginning of your article you say that a workflow is a kind of task, which is not bound to any specific thread, process or even computer. Unfortunately I miss this issues in your example. Your activities live all in one process, which I cannot just stop and restart on another machine.

Would you mind to give a brief summary of how to design a workflow, which can meet that requirement. How is the workflow runtime to start in that case? Or would such a summary result in a new article?

I think that an application starting, collecting some data and suspending on one machine, then being send via email and resuming on recipient's machine would produce a true WOW-effect and underline the idea of WF.

Think for example of a following workflow:
1. You let the user put 3 questions.
2. The user freezes the application and sends it via email to his friend
3. His friend resumes the workflow and sees the questions. He answers 2 of them, freezes the workflow and sends it back
4. The user resumes the workflow and sees the statistics (i.e. 2 of 3 questions answered)

I only mentioned the fact that WF applications are thread and process agile as "background info" about the technology. My sample app was far too simplistic to allow for passivation and resumption to be shown. Including that would have defeated the purpose of it being "The World's Stupidest WF Application."

The topic of workflow passivation and the intrinsic support for (de)serialization is far too involved to be explained in a comment on a messageboard. As you mentioned, it would require a separate article. Luckily for us, Dino Esposito has already written just that![^]

I am still usure about the motivation: It seems more like an ecercise what you have to do to save applicaiton state (which in a managed environment could probably be solved generically - but maybe with insanely big snapshots)

Thanks peterchen. The problem with creating an introductory article on a new technology is that the example app has to be simple enough to just explain the basics, but it will never convey the full breadth and applicability of that technology. There is much more to WF than just the things I presented. It is more than just a way to save the state of your application, it's a way of designing and creating an application. It's a way of declaring the flow of your application in a markup language, or even a Domain Specific Language. It's much more than I explained in the article, but I didn't want to overload the article with introductory "What is WF" material.

It wasn't intended as criticism of your article, just as general observation.
(And maybe a *hint hint* for an article about what can be done with WF....)

Your article certainly gives an idea what WF is about, and how to get started practically (which is IMO the most important part). I still don't know why I should do it - but that's partly because I'm a luddite

And maybe a *hint hint* for an article about what can be done with WF....

That would be an interesting article, but I'm not "there yet." I'm still very much a beginner at WF and am grappling with the concepts involved. Perhaps if I work with WF long enough I'll have the experience/perspective necessary for creating an article like that. Until then, all we can do is hope that someone who has that experience/perspective decides to write it first!

The interesting thing about MS's workflow engine is that yes, it does preserve state, but it does so within the context of a "process". So, instead of having to code the process (such as the steps from a work order to billing to accounts receivables), you construct a workflow (graphically, I might add). Now the workflow engine manages the state of the workflow, so you don't have to, and also the logic--the decision points, etc., which can include timed events (for example, if QA hasn't approved the work within 15 days, find out why).

And the most interesting thing that I saw at the MSDN event where WF was demonstrated was that you can change the workflow without bringing down all the applications. Now, how they can do this if you change something that interacts with the workflow's current state, I didn't ask that question. But it's pretty useful. For some reason though, Microsoft thinks that there will be a lot of ISV's providing lots of "workflow snippets". Reminds me of the promises of web services and BPEL and the like--all these computers and services communicating between each other. I personally think Microsoft is smoking something when they think we'll be seeing workflow snippets. Because, the whole point of a workflow, is that it is tailored to your business processes. How one can write some general proceses, well, I suppose you could put together some templates that can be customized, but I can't imagine that being any major revenue source for an ISV.

The other thing that's interesting is that it seems that WF can be used not only for "temporal business processes" but also as a simple scripting tool. For example, I use workflows in my Interacx system simply as a scripting mechanism for common, repeatable, steps, such as loading a view, binding controls to the view, creating a sandbox, managing transaction logs, handling user events, etc. And I think WF is extensible, so for example, you can write plugins that add workflow processes, again something I do with my own system. What I don't do with my system is manage state, so it's not a true business process workflow engine. At some point, I'm planning on looking at WF and seeing if it actually can meet both ends of the spectrum.

Nice article, BTW, Josh! It's nice to see the XAML, something they didn't show at the MSDN event. But, harhar, I did get to plug MyXaml when I was at the Albany event, I told them workflow's are great, and I'd been using it with my open source MyXaml parser for years.

People are just notoriously impossible. --DavidCrowThere's NO excuse for not commenting your code. -- John Simmons / outlaw programmerPeople who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith

People are just notoriously impossible. --DavidCrowThere's NO excuse for not commenting your code. -- John Simmons / outlaw programmerPeople who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith

I'm still missing something in regards to the usefulness... I can see it there, but I can't quite put my fingers on it. From what I can tell so far it's a powerful state machine, but I just don't understand how powerful quite yet.

Gotta study some more. Ironically, reading all of that marketing babble on Microsoft's sites is more of a turnoff than anything.

Here's my take on the matter (after muddling around with workflows and state machines with MyXaml):

I think part of the confusion of this is that WF crosses boundaries. Marc's definition of a workflow is a linear sequence of instructions. Whereas Marc's definition of a state machine is something that manages state (duh), executes instruction on entering, leaving, and transitioning state, and that has rules regarding the conditions on how you transition from one state to another.

Things get murky quickly. A workflow, by my definition, is rather limited. On the other hand, a state machine, by my definition, doesn't embue the concept of sequential steps, unless those are somehow coded into the rules of the state transitions themselves. I've done that, and it becomes an ugly mess because state and process start to get muddled.

Therefore, state and process are things that are really two separate things. A document can be said to be in a particular state during the process, but that's fairly obvious and not necessarily required. Conversely, state tells you about what processes can be performed if certain criteria are met.

WF takes my limited definition of workflow and makes it something more useful by adding rules to determine what state change the document undertakes during its processing. The process is "driven". Sometimes a process is driven by the fact that all the criteria are met (takes me back to my first article on organic programming), and sometimes a process is driven simply by the fact that a step in the process is completed. In any case, the salient thing is that the process is driven. This is something a state machine doesn't do intrinsically. WF is the driver, as it were.

To put it succinctly, a state machine is static, and a workflow is dynamic.

Now, one of the interesting artifacts of a workflow engine (and much less so, but potentially, a state machine) is that the processes become encapsulated, autonomous, and hopefully small but useful pieces of code. The power of workflows is how they create an environment in your code in which processes are decoupled from one another. They become unentangled, more easily unit tested, possibly portable, possibly distributable, and potentially multithreadable. Workflows are a very, very powerful way of plugging in new functionality and swapping out bad or obsolete functionality, because most of the time you're not touching the core code and the workflow engine has given you an architecture that promotes those qualities.

And that is what Microsoft's Workflow Foundation is, IMO.

As an example, I used workflows 10 years ago in a C++ product that cashes out entertainers after a night of, well, entertaining. The workflow was comprised of calls to very simple methods for DB and UI interaction. When a client requested a change to their cash out process, 95% of the time it involved a change in the workflow, not the underlying application. We could also easily maintain different workflow scripts customized to different clients. And to this day, I'm still editing workflow scripts for the majority of client driven changes the product undergoes.

And that is another thing about Microsoft's Workflow Foundation: in the right environment, the customer can have the power to manage and modify their workflows as their business model and processes change and develop. It's like Legos for both programmers and customers. As programmer, you just have to code the right shape and color pieces.

People are just notoriously impossible. --DavidCrowThere's NO excuse for not commenting your code. -- John Simmons / outlaw programmerPeople who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith

Wow! Excellent information and perspective, Marc. Thanks a lot for enhancing my understanding of WF (and my article, for that matter!). I feel like your "dissertation", as you put it, should be my article, and my article should be a comment!

People are just notoriously impossible. --DavidCrowThere's NO excuse for not commenting your code. -- John Simmons / outlaw programmerPeople who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith

People are just notoriously impossible. --DavidCrowThere's NO excuse for not commenting your code. -- John Simmons / outlaw programmerPeople who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith

I'm still missing something in regards to the usefulness... I can see it there, but I can't quite put my fingers on it. From what I can tell so far it's a powerful state machine, but I just don't understand how powerful quite yet.

Be sure, that although here on codeproject you can find some nice examples of small standalone state machines, they are at first try "faster", but not so well scallable as WF. Big ASP.NET system with integrated WF will have good power even on high load, IMHO. Sure, that everything which is well written for .NET runtime as multithreaded, is "by design" internally scallable to multi core CPU and MPS too, which IS cool

Hmm I've been busier studying WPF and WCF lately, but now that you mention it, it looks like it's also perfect for distributed processing of the SETI/Folding@Home type -- although I guess those are relatively simpler examples in terms of workflow.

It's a shame that all the everything Microsoft makes these days takes forever to explain. Whoever manages to explain .NET to a developer in under 10 minutes deserves a nobel prize.

I personally think Microsoft is smoking something when they think we'll be seeing workflow snippets. Because, the whole point of a workflow, is that it is tailored to your business processes. How one can write some general proceses, well, I suppose you could put together some templates that can be customized, but I can't imagine that being any major revenue source for an ISV.

Many years ago, I worked for a company that did provide templates for a workflow system (theirs). Effectively, they would give you the workflow engine for free, but you bought the templates and customisation services from them.

In certain industry sectors (such as insurance or reinsurance), this attitude makes a lot of sense because the general processes are the same, and it's only in minor details that the systems differ.

Arthur Dent - "That would explain it. All my life I've had this strange feeling that there's something big and sinister going on in the world."
Slartibartfast - "No. That's perfectly normal paranoia. Everybody in the universe gets that."