Using Windows Workflow Foundation with ASP.NET 2.0

Mar 4, 08:15 pm

Author: Tom Fischer
Editor: David Schultz
Reviewer(s): Damien Foggon, Teun Duynstee

Introduction

Because Windows Workflow Foundation (WF) is a relatively new technology, I'll start with a quick introduction to the subject (you can find a more detailed introduction in Morgan Skinner's article). Before explaining why Windows Workflow simplifies business process development it helps to understand what business processing entails. Unfortunately, like so many other terms it means many things to many people. Fortunately, our usage in this article is quite simple - a collection of tasks acting together to achieve a specific business result. Placing a sales order at Company XYZ exemplifies a typical business process. Completing it might involve four distinct tasks: collecting order information, processing payment, checking inventory and shipping product.

Given this understanding of business processes it turns out that they predictably call upon several common supporting services having very little to do with any specific business goal. In the aforementioned Company XYZ example, the process may span several days and require intermediate states to be stored then retrieved (a process that's known in WF parlance as dehydration and re-hydration). It might also call upon transactional support, asynchronous processing, notification services, etc. Why would developers want to waste time constructing these common business processing services?

That's where the Windows Workflow Foundation (WF) comes to the rescue. It provides many of the supporting services expected of a typical business process application. But wait, there's more!

It turns out that the individual tasks of a typical business process rely on a common set of software activities. For example, most of Company XYZ sales and order processing tasks utilize the same conditional logic constructs, database lookups and security permission checks, etc. Once again, given this commonality why would developers want to waste time coding these common software components? They don't. Windows Workflows provides many such items, known as activities.

The final piece in the puzzle of understanding how Microsoft eased business process development takes us directly to the Windows Workflow Foundation object model. Figure 1 shows how two important objects, the WorkflowInstance and WorkflowRuntime objects, bring together all of the Windows Workflow Foundation services and activities.

Figure 1. Partial Windows Workflow Foundation Object Model

This article focuses on understanding the WorkflowInstance and WorkflowRuntime objects in an ASP.NET environment. Along the way we explore how they work with some of the other Windows Workflow Foundation services and activities.

System Requirements

Working through the samples requires installation of the Windows Workflow Foundation. This can be accomplished in a few ways, but most readers will find it easiest to simply install the Visual Studio 2005 Extensions noted below.

About The Sample Code

There is no sample code supplied with this article because I've chosen instead to refer to the Microsoft tutorial samples in order to explain what WF is about.

The Windows Workflow Foundation Beta 2 SDK section entitled Windows Workflow Foundation Samples contains the code discussed in this article. You should install the following two referenced sample applications:

  • Help Desk Support - demonstrates passing information between an ASP.NET application and Windows Form application.
  • Web Service Sample - demonstrates exposing a workflow behind a web service.

You should bear in mind that:

  • The SDK contains complete installation instructions.
  • I found that most of the sample applications work well. Keep in mind that they all run on beta software and this may prove frustrating at times. For example, the Using Persistence Services application needs the Distributed Transaction Coordinator (DTC) service.
  • Playing with any sample Windows Workflow control's visual designer will most likely require rebuilding the solution.

Windows Workflow Basics

Designing and building business process applications without a firm understanding of Windows Workflow basics only promises pain to an architect or developer. Ill-informed use of the technology within an ASP.NET application only adds to the hurt. Therefore, we will begin with the two dramatis personae of Windows Workflow, WorkflowRuntime and WorkflowInstance.

WorkflowRuntime and its Friends

Starting our discussion with the WorkflowRuntime is not an arbitrary decision. While WorkflowInstance and the Activity objects may ultimately prove more fun and fascinating to a .NET developer, the WorkflowRuntime does the heavy lifting as shown in Figure 2.

Figure 2. WorkflowRuntime Class Diagram

Several behaviors not evident from the class diagram are worth noting. First, one and only one WorkflowRuntime runs in an AppDomain, more commonly known as the Host in Windows Workflow parlance. One technique demonstrated in the SDK Help Desk Support sample application is how to avoid accidentally working with too many WorkflowRuntime references. It utilizes the Cache as the source of truth when accessing and creating the singular WorkflowRuntime. This snippet shows how to create a WorkflowRuntime, and ensure it can be accessed later on.

WorkflowRuntime workflowRuntime = (WorkflowRuntime)
  HttpContext.Current.Cache[WorkflowRuntimeCacheKey];
if (workflowRuntime == null)
{
  workflowRuntime = new WorkflowRuntime();
  HttpContext.Current.Cache[WorkflowRuntimeCacheKey] = workflowRuntime;
}

Second, just as only one WorkflowRuntime is allowed for one AppDomain, only one Type with the same name may run within a WorkflowRuntime. Changing a service type will at a minimum require dropping the loaded Type and adding the new one. There is one final sticking point worth remembering when adding and dropping services. Those labeled Core Services in Figure 2 can only be loaded or unloaded when the WorkflowRuntime is not running.

Note: In those rare cases where a second instance of the same service is still needed a workaround exists. WorkflowRuntime is not a choosy creature. It happily loads a subclass of an already loaded parent type.

At this point in our discussion ASP.NET developers may rightfully wonder about the flexibility of the WorkflowRuntime. Once a WorkflowRuntime loads, abandon all thoughts of safely altering it. The WorkflowRuntime houses any and all loaded WorkflowInstance objects in the entire AppDomain - not just those of a given session or page. Changing the WorkflowRuntime or any of its services may adversely impact other WorkflowInstance objects.

The Services

Developers familiar with plug-in and framework architectures tend to be surprised by the WorkflowRuntime.AddService(object service) method's parameter type - object. Almost anything can be added. WorkflowRuntime behaves much like a container. Despite these possibilities, many Windows Workflow applications will usually load the following services:

  • SqlTrackingService - Derived from TrackingService, uses a SQL Server database to store workflow tracking information.
  • SqlWorkflowPersistenceService - Derived from WorkflowPersistenceService, uses a SQL database to store workflow state. WorkflowPersistenceService defines the necessary magic for dehydrating and hydrating workflow state.
  • DefaultWorkflowTransactionService - Derived from WorkflowTransactionService, loads automatically and maintains consistency between the state of a WorkflowRuntime and its data store.
  • CustomDataExchangeService - Derived from ExternalDataExchangeService, these custom classes handle communications between WorkflowRuntime and its hosting AppDomain.

Notice how all the classes listed here are derived from other classes. That's not a coincidence: Windows Workflow sports a very flexible API. For example, one of the SDK sample applications shows how to write a custom tracking provider.

Windows Workflow Foundation provides many other services too. Some of them developers will explicitly load for a specific purpose, as with SqlWorkflowPersistenceService, and others seemingly are loaded automatically. Figure 3 shows a screenshot of a running Help Desk Support application demonstrating the variety services to be found within a running WorkflowRuntime.

NOT VALID: ImageTooWide: Sample Visual Studio Locals Window
This figure has been reduced in size to fit in the text. To view the full image Click here

Configuring a Service

Configuration options will hopefully erase any unfavorable WorkflowRuntime impressions created in the previous discussion of the ensuing difficulties of managing services. They can be configured with one line of code as shown below for a SqlWorkflowPersistenceService.

workflowRuntime.AddService(
  new SqlWorkflowPersistenceService(connectionString));

And if that's inconvenient, the web.config file works equally well.

<configSections>
 <section name="WorkflowRuntime"
  type="System.Workflow.Runtime.Configuration.WorkflowRuntimeSection,
  System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, 
  PublicKeyToken=31BF3856AD364E35"/>
</configSections>
<WorkflowRuntime>
 <Services>
  <add type="System.Workflow.Runtime.Hosting.SqlStatePersistenceService,
  System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral,
  PublicKeyToken=31BF3856AD364E35"
  ConnectionString="Data Source=localhost\SQLExpress;
    Initial Catalog=WorkflowPersistence;Integrated Security=True;"/>
 </Services>
</WorkflowRuntime>

Most web applications will opt for a web.config based configuration. Doing so simplifies web farm deployment, as well as, development effort since coders can use a local instance of SQLExpress as shown above.

Life on the Farm

Configuring the Windows Workflow WorkflowRuntime running as part of web server farm could not be easier. Most workflow state of any interest is persisted by SqlWorkflowPersistenceService and SqlTrackingService, each of which uses their own specialized database. Therefore, sharing state between several servers in a web farm only requires instantiating these services with the connection string pointing to the same database.

Note: These two specialized databases are created via SQL scripts. These scripts may be found at %WINDIR%\WinFX\v3.0\Windows Workflow Foundation\SQL\<language>\. The SDK explains how to install theses databases when working with SqlWorkflowPersistenceService and SqlTrackingService.

Some Thoughts on WorkflowInstance

Let us now focus our attention to the soul of Windows Workflow - WorkflowInstance. It encapsulates the business processing. Within a workflow resides one Activity, the root, which holds several other Activity objects. How all these activities interact with each other constitutes the business process. But before discussing activities, let us first look into managing WorkflowInstance objects on the web.

Workflow instances are created by providing the workflow type. One of the easiest of several ways of doing so is shown below.

WorkflowInstance workflowInstance =
  workflowRuntime.CreateWorkflow(typeof(SomeWorkflow));

Guid objects identify existing WorkflowInstance objects, which the read-only property, WorkflowInstance.InstanceId, exposes. Its string representation can provide the link between WorkflowInstance and Web.UI.Page as exemplified below.

Guid workflowInstanceId = (Guid)Session["workflowInstanceId"];

With InstanceId in hand, resituating a WorkflowInstance saved earlier in the session only takes a line of code.

WorkflowInstance workflowInstance =
  workflowRuntime.GetWorkflow(workflowInstanceId);

Unloading a WorkflowInstance demonstrates another nice feature of the framework. Calling WorkflowInstance.Unload() automatically calls the WorkflowPersistenceService service.

While playing with persistence there lurks a potential hazard. WorkflowPersistenceService allows a long running workflow's state to be saved, as mentioned earlier, a process also known as dehydration, and later resurrected or re-hydrated. Developers must take care when moving between these two states. WorkflowInstance objects do not automatically remember anything accomplished between dehydration and re-hydration unless explicitly saved. For example, an Activity object could unintentionally execute a second time if its WorkflowInstance was not saved during a prior dehydration-hydration cycle.

So much for WorkflowInstance minutiae, let us now consider some general observations about their workhorses - Activity objects.

Activities, Activities and more Activities

The designing and building of Activity objects is a gigantic topic. Readers will discover that most published material on Windows Workflow focus on it. This should not surprise anyone since Activity objects are the building blocks of business processing programming. The discussion here will hopefully provide a helpful introduction to activities by looking at their basic types by functionality.

  • Root - All WorkflowInstance contain either a SequenceActivity or StateMachineWorkflowActivity object. All other activities are placed within these two container activities. This may not be obvious when working with Visual Studio, selecting one of the Visual Studio workflow templates (see Figure 4) adorned with a red arrow automatically puts the appropriate root Activity in play.
  • NOT VALID: ImageTooWide: Visual Studio Workflow Templates
    This figure has been reduced in size to fit in the text. To view the full image Click here

  • Programming Logic - Several out of the box Activity objects provide flow control, such as, ParallelActivity and IfElseActivity. Some are surprisingly complex and may require a little effort to master. The ConditionedActivityGroup might be the best example of such an activity.
  • State - State Machine workflows enjoy their own dedicated collection of activities. They facilitate the mechanics of the Windows Workflow's version of a state machine.
  • Utility - A gaggle of activities that handle a diverse array of functionality, such as, communicating with a web service (InvokeWebServiceActivity); listening for events (ListenActivity); and waiting a preset time (DelayActivity).

Custom activities are one notable omission from the above list. Their very nature defies simplistic categorization. Developers can build them to handle utility tasks, such as reading an XML schema, or to perform complex business processing logic utilizing a combination of other Activity objects.

Note: The Microsoft Windows Workflow Site offers a growing collection of free, downloadable utility activities. See the Related Links section for more information.

State or Sequential?

Previous discussions omitted a critical WorkflowInstance design question. Is the workflow going to perform sequential processing or something akin to a state machine? The answer not only determines the root activity but whether or not the WorkflowInstance might require a StateMachineWorkflowInstance wrapper.

Applying the StateMachineWorkflowInstance is not difficult as shown in the following few lines of code.

WorkflowInstance wi = workflowRuntime.CreateWorkflow(workflowType);
// Wrap the WorkflowInstance
StateMachineWorkflowInstance smwi = 
  new StateMachineWorkflowInstance(workflowRuntime, wi.InstanceId);
wi.Start();

The difficult part is knowing whether or not a workflowType (a.k.a. root Activity) needs wrapping. For example, bugs arising from an incorrectly loaded StateMachineWorkflowActivity within a web application may not readily show themselves until several users communicate with several different instances of an Activity object.

What about that WorkflowWebHostingModule?

The mysterious WorkflowWebHostingModule module shows itself under at least two scenarios. The first may occur when exposing an Activity via a web service. The second certainly arises when employing either of the WebServiceInputActivity or WebServiceOutputActivity activities. Whatever the scenario, this module helps coordinate WorkflowInstance objects and their consumers.

Coordination via WorkflowWebHostingModule is not without costs that developers must remain cognizant of. One of the loaded services, ManualWorkflowSchedulerService, places the ASP.NET application in a single thread mode and thus affects scalability. Also, the web service uses cookies to manage state, clients must allow cookies.

ASP.NET Windows Workflow Design Options

Employing Windows Workflow in ASP.NET initiates one of two business processing design options.

For the sake of simplicity I'll call one of these options Local and the other Enterprise workflow. The SDK includes two samples applications demonstrating each of these approaches.

One last word before continuing, both Local and Enterprise workflows may harmoniously exist in one solution. One does not preclude the other. But it is important to remain mindful of our earlier discussions about the WorkflowRuntime. ASP.NET architects might be in for a rude surprise if they discover that the supporting services of the Activity objects associated with each of these design options conflict.

Local Workflow

The Local design option directly controls the end user's experience via a WorkflowInstance. It links the user interface, in our case web forms, with the business processing logic. The Windows Workflow Foundation SDK Help Desk Support sample application offers an excellent sample of this tack.

Solution Overview

The sample application includes both a Windows forms and web user interface version. We will be look at the later version as shown in Figure 5.

Figure 5. Web Application Example.sln Solution Explorer Window

  • HelpDeskWebApp - The user interface with five web forms that HelpRequestWorkflow controls.
  • HelpRequest - Project housing the HelpRequestWorklow activity that provides the business logic and controls the user interface.
  • LocalServiceContract - Implements an ExternalDataExchangeService, CustomDataExchangeService, and several other supporting objects necessary for HelpRequestWorklow to communicate with the ASP.NET WorkflowRuntime instance.
  • SimpleReadWriteActivites - Contains two not so simple utility Activity objects, ReceiveData and SendData. Together they wrap LocalServiceContract objects into data pipes linking web page and workflow.

LocalServiceContract contains the underlying technical brains of the application, DataAccess and its collection of WorkflowDataAccess objects. Together they keep the different web forms dealing with help desk actions synchronized with the workflow instance as visualized in the communications graphic in Figure 6.

Figure 6. Help Desk Support’s Communications

Underneath DataAccess is Windows Workflow's correlation mechanism. It provides the mechanism for ensuring the right messages come and go to the rightful owners.

Architectural Considerations

If the technical tour de' force of the Help Desk Support design does not quite sell its adoption for local workflows, that's understandable. But I suspect it is not anymore difficult to implement than a sophisticated Model-View-Controller design or a production shopping basket pattern. Notwithstanding this fact, it remains to be seen whether or not a better design will arise that enables a WorkflowInstance to coordinate several ASP.NET pages.

Enterprise Workflow

The Windows Workflow SDK Web Service Sample addresses the second design option. One readily available workflow encapsulates the business processing code. The design option's name comes from the fact that the workflow is (1) an enterprise business process and (2) accessible to other processes. Figure 7 describes this design that we will see in the sample application.

Figure 7. Example of Exposing a Workflow via a Web Service

In Figure 7 we observe a client workflow, WorkflowInvoke, calling upon a server workflow, WorkflowPublish, via a web service page. Appreciating the utility of this design requires imagining the all important enterprise workflows being exposed via WorkflowPublish. Suffice to say, the sample does not include such things.

Solution Overview

The solution structure as shown in , WebService.sln, is remarkably simple compared to the last sample.

Figure 8. WebService.sln Solution Explorer Window

Even the briefest of reviews will convince most readers that the sample solution serves as a good demonstration. Nonetheless, it requires little imagination envisioning WebServicePublishWorkflow as a complex enterprise business process to be consumed by another workflow.

Communications with WebServicePublishWorkflow does not have to be via another workflow. I would propose to the more ambitious reader the exercise of exposing WebServicePublishWorkflow via a straightforward web method!

One quirk of publishing a workflow via a web service is its impacts on the web application. As discussed previously, if the web service utilizes WorkflowWebHostingModule it places the hosting ASP.NET processing in a single thread mode. This suggests prudence when coding such workflows, it best be quick and use an asynchronous processes where possible. Load testing borders on mandatory in order to determine how many servers may be required!

Architectural Considerations

I find it the practicality and simplicity suggested by the sample application for building high quality enterprise business processes with minimal effort quite striking. The Windows Workflow Framework handles much of the plumbing associated with today's business processing requirements. So while the wizard driven workflow project publishing may prove too weak for production purposes, the technology looks flexible and solid.

Conclusion

The Windows Workflow Framework enables business processing applications to be built in a efficient and consistent manner. Exploiting it only requires architects and developers to work within a few boundaries. Fortunately, Microsoft provides an easily configured and extended framework to overcome most barriers. This article introduced a few Windows Workflow concepts and their place within ASP.NET. Hopefully our discussion will ease implementing your own first Windows Workflow web applications.

Founders at Work



Add your comments

Please keep your comments relevant to this blog entry: inappropriate or purely promotional comments may be removed. To add hyperlink, please follow this example: "your link text":http://your.link.url