Tuesday, February 27, 2007

* Tutorial : Developing a state machine workflow

In this post i will demonstrate how to build a basic state machine workflow.

A state machine workflow consists of set of states with one state marked as 'start' state and one as 'final' state. Every state has an event associated with it and based on those events, workflow transitions from one state to another. It always starts from 'start' state and once it reaches the 'final' state, the workflow is assumed to be complete.

Few points about composition of a state machine workflow :

  • Every workflow consists of set of 'StateActivity'.
  • Each state is made up of one or more 'EventDrivenActivity', can contain one 'StateInitializationActivity' and can contain one 'StateFinalizationActivity'.
  • Each workflow has two properties 'InitialStateName' and 'CompletedStateName' to set the start and final state.
  • Wokflow can be transitioned from one state to another using 'SetStateActivity'.

Following are the steps to create a state machine workflow using Visual Studio 2005 and WF extensions for Visual Studio.

  • Start by creating an empty workflow project. Change the 'Output Type' to console application.
  • Add a new Item to the project : 'State machine workflow - with code separation' - Workflow1.xoml
  • Automatically a state will be added to workflow - Workflow1InitialState and the InitialStateName of the workflow has been set to Workflow1InitialState .
  • Drag and Drop two more states to the workflow. Name one as 'middleState' and the other as 'finalState'
  • Set the 'CompletedStateName property of workflow to 'finalState'
  • Drop an EventDrivenActivity to start state and within that drop a delayActivity, codeActivity and SetState Activity.
  • Set the delay for delayActivity say 5 sec.
  • Add code to code activity as follows :
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("In code activity of start state");
}








  • Set the TargetStateName property of SetStateActivity to 'middleState'.

  • In middle state activity, add an EventDriven activity and into it add a delayActivity, code activity and set state activity.

  • Set the TargetStateName property of SetStateActivity to 'finalState'.

  • Add code to code activity as follows :
private void codeActivity2_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("In code activity of middle state");
}








  • Add a code file to the project for creating entry point for the program and hosting/executing the workflow.
using System;
using System.Threading;
using System.Workflow.Runtime;

namespace SimpleStateMachine
{
static class MainProgram
{
static AutoResetEvent waitHandle = new AutoResetEvent(false);

static void Main()
{
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
try
{
workflowRuntime.StartRuntime();
workflowRuntime.WorkflowCompleted += OnWorkflowCompleted;
workflowRuntime.WorkflowTerminated += OnWorkflowTerminated;

Type type = typeof(Workflow1);
workflowRuntime.CreateWorkflow(type).Start();

Console.WriteLine("Running the workflow. Waiting for the timer events...");

waitHandle.WaitOne();
}
catch (Exception e)
{
Console.WriteLine("Encountered an exception. Exception Source: {0}, Exception Message: {1} ", e.Source, e.Message);
}
finally
{
if (workflowRuntime != null)
workflowRuntime.StopRuntime();
Console.WriteLine("WorkFlow Completed");
}
}
}

static void OnWorkflowCompleted(object sender, WorkflowCompletedEventArgs instance)
{
waitHandle.Set();
}

static void OnWorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
}
}
}








  • The layout file for the workflow will look somewhat like following :
<StateMachineWorkflowDesigner xmlns:ns0="clr-namespace:System.Drawing;Assembly=System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Name="Workflow1" Location="30, 30" Size="668, 554" AutoSize="False" AutoSizeMargin="16, 24" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<StateMachineWorkflowDesigner.DesignerConnectors>
<StateDesignerConnector TargetConnectionIndex="0" TargetStateName="middleState" SourceConnectionIndex="0" TargetConnectionEdge="Top" SetStateName="setStateActivity1" SourceStateName="Workflow1InitialState" SourceConnectionEdge="Right" TargetActivity="middleState" SourceActivity="Workflow1InitialState" EventHandlerName="eventDrivenActivity1">
<StateDesignerConnector.Segments>
<ns0:Point X="193" Y="110" />
<ns0:Point X="294" Y="110" />
<ns0:Point X="294" Y="341" />
</StateDesignerConnector.Segments>
</StateDesignerConnector>
<StateDesignerConnector TargetConnectionIndex="0" TargetStateName="finalState" SourceConnectionIndex="0" TargetConnectionEdge="Top" SetStateName="setStateActivity2" SourceStateName="middleState" SourceConnectionEdge="Right" TargetActivity="finalState" SourceActivity="middleState" EventHandlerName="eventDrivenActivity2">
<StateDesignerConnector.Segments>
<ns0:Point X="361" Y="382" />
<ns0:Point X="500" Y="382" />
<ns0:Point X="500" Y="190" />
<ns0:Point X="412" Y="190" />
<ns0:Point X="412" Y="198" />
</StateDesignerConnector.Segments>
</StateDesignerConnector>
</StateMachineWorkflowDesigner.DesignerConnectors>
<StateMachineWorkflowDesigner.Designers>
<StateDesigner Name="Workflow1InitialState" Location="46, 69" Size="160, 80" AutoSizeMargin="16, 24">
<StateDesigner.Designers>
<EventDrivenDesigner Size="110, 292" Name="eventDrivenActivity1" Location="54, 100">
<EventDrivenDesigner.Designers>
<DelayDesigner Size="90, 40" Name="delayActivity1" Location="64, 172" />
<CodeDesigner Size="90, 40" Name="codeActivity1" Location="64, 242" />
<SetStateDesigner Size="90, 50" Name="setStateActivity1" Location="64, 312" />
</EventDrivenDesigner.Designers>
</EventDrivenDesigner>
</StateDesigner.Designers>
</StateDesigner>
<StateDesigner Name="middleState" Location="214, 341" Size="160, 80" AutoSize="False" AutoSizeMargin="16, 24">
<StateDesigner.Designers>
<EventDrivenDesigner Size="110, 292" Name="eventDrivenActivity2" Location="309, 148">
<EventDrivenDesigner.Designers>
<DelayDesigner Size="90, 40" Name="delayActivity2" Location="319, 220" />
<CodeDesigner Size="90, 40" Name="codeActivity2" Location="319, 290" />
<SetStateDesigner Size="90, 50" Name="setStateActivity2" Location="319, 360" />
</EventDrivenDesigner.Designers>
</EventDrivenDesigner>
</StateDesigner.Designers>
</StateDesigner>
<StateDesigner Name="finalState" Location="332, 198" Size="160, 80" AutoSizeMargin="16, 24" />
</StateMachineWorkflowDesigner.Designers>
</StateMachineWorkflowDesigner>








  • Execute the workflow .. the successful output will be :


Running the workflow. Waiting for the timer events...
In code activity of start state
In code activity of middle state
WorkFlow Completed



~tata & take care~



Other Posts



3 comments:

  1. lost me at: "and within that drop a delayActivity, codeActivity and SetState Activity" All my drops disallowed by the IDE. What does 'within that' mean? Within what exactly - excuse my asbergers!

    ReplyDelete
  2. Hi,
    You need to drop those activities in EventDrivenActivity. For dropping in it you need to double click EventDrivenActivity which will expand it and you can drop other activities inside it. Hope this solves the issues.

    ReplyDelete
  3. Technology is the application of maths, science, economics and the arts for the benefit of life as it is known.

    ReplyDelete