In my last post I discussed the general architecture of WF and made mention of its three main points of extensibility: hosts, activities and services. In this post I am going to focus in on hosting. Let’s begin with a code sample demonstrating the most basic hosting code:
If you create a new workflow console application, VS will generate something like the code above. While this code is generally not suitable for a production environment, it will serve to illustrate several important points about WF. First, note the use of the WorkflowRuntime class. This class, aptly named, manages all aspects of executing workflows at runtime. This is the class that allows such flexible hosting of WF. Instantiating WorkflowRuntime brings the power of WF to bear in whatever ApplicationDomain you need it, be it in an ASP.NET app, a Windows Service, WCF Service, WPF app, etc. Notice that this class implements IDisposable, so you should deal with it appropriately (illustrated nicely here by the using block). Once you instantiate the runtime, there are three general things that you will want to do with it: subscribe to its events, add/remove services and create workflows. Services will be discussed in a later post, but the other two points I will address here. The runtime exposes a number of events related to the lifecycle of the workflows that it is hosting. The two most important events are illustrated above. WorkflowCompleted fires when a workflow completes successfully and WorkflowTerminated fires when a workflow shuts down abnormally. Each event provides a custom EventArgs containing information typically needed to handle these events, including a reference to the WorkflowInstance that triggered the event.
Once you have instantiated the runtime and hooked up the appropriate events (and possibly added services) you will be ready to kick things of. To proceed, call CreateWorkflow on the runtime. Calling this method will return a WorkflowInstance object. Calling Start on the instance will initialize the workflow and cause the first activity to begin executing.
You may have noticed that I left some important information out of my explanation so far. Such as: How does the runtime know what the workflow is and what is the deal with the AutoResetEvent? To address the first question (partially), the CreateWorkflow method has a number of overloads each of which accepts a different set of information allowing the runtime to create a WorkflowInstance. In the above example, the runtime uses reflection to instantiate a workflow based on its Type. Workflows can also be instantiated from Xaml definitions or by custom mechanisms. I will discuss workflow creation more in my next post. The presence of the AutoResetEvent reveals an important detail about how workflows are executed. We must call WaitOne on the application’s thread in order to prevent the application from shutting down before the workflow finishes executing because WorkflowInstance.Start is NOT a blocking call. When the WF team implemented the WorkflowRuntime they made a critically important decision to use a multithreaded model for workflow execution. It is this decision along with other related architectural choices that allow WF to scale and support long running workflows. The above example is overly simplified and assumes that only one WorkflowInstance will be running at any given time. In most scenarios where you would need/want to use a workflow engine, you are likely to have many instances running at any given time. Perhaps these instances are managed by a WCF service (or set of services) that represents your core business. It is this reason, primarily, why I mentioned that the above code is generally not production ready. If you were to host in a WCF service, for example, you would likely want a static instance of the WorkflowRuntime and a way of managing all of the WorkflowInstnaces that you created and started. Sam Gentile has suggested writing a wrapper class for the WorkflowInstance in order to facilitate management. I implemented a similar solution when we were designing the AI for our game. This seems to be a generally good practice for real world scenarios; however I would appreciate some official guidance from the WF team on this subject.
NEXT POST: Workflows and Activities
03-18-2007 5:52 PM