Contents
Other FAQs
- Silverlight FAQ Part 1: Click here
- Silverlight FAQ Part 2: Click here
- Silverlight FAQ Part 3: Click here
Introduction
All characters in this article are fictional and any resemblance to anyone live or dead is purely coincidental.
This is a nice talk between Mr. RC and Mr. Shiv about state machine workflows. RC starts talking about an order project and they end up in a nice discussion which gives us a step by step approach of how to execute a state machine workflow.
This article was written in a straight half an hour session so please excuse my English as it’s my second language and any spelling mistakes. So guys. enjoy state machines.
The State Machine Workflow discussion
Ramprasad Chaurasiya: Hi Shiv, how’s things?
Shivprasad Koirala: Doing great RC (Ramprasad Chaurasiya).
RC: You have written more than 60 articles, that’s huge; looks like you are copy pasting articles from MSDN and other sources.
Shiv: Hmmm, can we talk something better before you reveal me completely :) ?
RC: I was reading your article on WWF: WWF.aspx. I am working currently on an order processing project and I am a bit confused about how the workflow aspect of the project should be approached.
Shiv: Can you explain to me the workflow part of your order project?
RC: OK, here’s the requirement for the order and I have drawn a small sketch of how the workflow looks like:
- The workflow starts by the user placing an order.
- The accounts department logs in and checks if the payment is made for the order. If the payment is not made, then they mark the order as cancelled and it’s sent to the user for payment.
- Once the user makes the payment, the order is moved to a valid order placed on stage again.
- Purchase department logs in and checks if the product is in stock for the order.
- If the product is in stock, the purchase department person enters saying the product is in-stock and the order is then ready for dispatch.
- Courier department logs in and checks if the address of the order is proper. If the address is not proper, the order is moved to a pending stage and sent to the end user for address correction.
- In pending stage, if the user corrects the address, the order is then moved back to ready for dispatch.
- If the order is dispatched and received by the end user, the delivery person marks the order as delivered.
Shiv: Hmmm, it’s an interesting workflow. This can be very easily solved by using Windows Workflow Foundation. The first step we need to decide is which kind of workflow we need to choose for the above.
RC: Ohhh, are there different kinds of workflows in Windows Workflow Foundation?
Shiv: Primarily there are two kinds of workflow in WWF and depending on the nature of our requirements, we need to choose the workflow accordingly.
RC: That’s funny, I thought a workflow is just a collection of activities which are executed depending on certain conditions. For instance, the below figure shows a simple workflow which has customer activities, and some conditions depending on which the activities are executed. In other words, what I want to say is a workflow is work flow. What do you mean by types of workflow?
Shiv: From the Windows Workflow Foundation point of view, there are two types of workflows: sequential workflow and state machine workflow.
A sequential workflow has clear start and finish boundaries. Workflow controls the execution in a sequential workflow. In sequential execution, one task is executed after another. Sequential workflow is more rigid in format and the execution path has a deterministic nature.
A State Machine workflow is more dynamic in nature. The workflow has states and the states wait for events to help it move to the next state. In a State Machine, the execution path is indeterministic in nature.
The below figure shows the visual conceptualization of the fundamentals. You can see that in sequential workflow, the execution path is very determent. Shiv performs the entire task sequentially and these tasks are very determent. Now have a look at the second workflow. Every state goes to another state when it receives external events. For instance, when Shiv is seeing Star Trek, there is an event of flashing news which triggers him to see the flashing news.
RC: In other words, we can say that if the workflow controls the execution then it is sequential and if there is some external factor which controls the workflow, then it becomes a State Machine workflow.
Shiv: Yes, that’s a good summary. Looks like you have started thinking in terms of workflows. So now let’s first decide which kind of workflow your order project is.
RC (thinking): Well, I think it’s a sequential workflow as the workflow has control on the execution.
Shiv: OK, so let me redraw your workflow diagram. Below is your changed diagram. You can see there are so many inputs from the user which changes your workflow. For instance, the accounts department depending on the payment diverts the workflow, the purchase department depending on the stock value diverts the flow, and the same holds true for the courier person.
RC: I understand where you are coming from. My workflow is not in control of itself. OK, I buy back my point that my order project is a State Machine workflow.
Shiv: A few comments on workflow types before we move ahead. Many architects get carried away with sequential workflows. If you see in your application that depending on user input your workflow is changing, then it’s a good idea to think about a State Machine. Let me comment from a more practical point of view. In actual projects, it’s a combination of these types rather than just one type. In other words, you can have a broader state machine workflow which has a lot of sequential workflows in between and vice versa.
RC: What I also think is we should also look from the domain perspective what kind of workflow it actually looks like. OK, this sounds good. How can we now move ahead?
Shiv: Let’s first try to visualize the important elements in a State Machine workflow. The three important things in a State Machine workflow are initial state, action, and final state. You can see from the figure a simple example of a State Machine. So you have an initial state, an action happens, and it moves to some other state. For instance, a bulb is first in on state and then switched off and it moves to off state.
RC: OK, I am trying to get a feel of State Machines now.
Shiv: Let’s first visualize the whole order workflow from these three aspects. Below is a table which shows the whole workflow from the above three perspectives.
First state | Action / Event | Next state |
Order placed
| InStockEvent
| Order approved
|
Order placed
| NotPaidEvent
| Order cancelled
|
Order cancelled
| PaymentMadeEvent
| Order placed
|
Order approved
| AddressNotProperEvent
| Order pending
|
Order pending
| AddressCorrectedEvent
| Order approved
|
Order approved
| DispatchedEvent
| Order delivered
|
RC: OK, that is a good visualization. What I understand is we have in all four different states and some 6 to 7 events. I think our State Machine diagram will look something like below:
Shiv: Nice that you are catching up on State Machines. Now that we are clear about our states and our events, it’s time to make the complete workflow using WWF.
RC: That makes sense. I really do not like theory, there should be some practical implementation.
Shiv: We will be using VS 2008 Enterprise and .NET 3.5.
RC: Why not Express edition?
Shiv: Well, WWF does not come with an Express edition.
RC: OK, noted.
Shiv: Before we move ahead and talk about the practical implementation, there’s one more point we need to cover. In a typical workflow project, we have two important things: the workflow and the client which can be a Windows or web application which consumes that workflow. In a State Machine workflow, we need to define an interface with all actions. This interface is the only thing which the workflow knows. So any client who wants to invoke the workflow should make calls using this interface.
RC: OK, got it, so this interface is the gateway to make calls to the workflow.
Shiv: Yes, you said it right. Below is our interface. The first step we need to do is create the interface. The below figure shows that we have created an IOrder.cs interface. The important point to note is we have referenced System.Workflow.Activities
and attributed the interface with ExternalDataExchange
. We have then defined all our events for the states in this interface.
RC: That’s a pretty simple step.
Shiv: OK, now add a new project and select ‘State Machine Workflow Library’.
Shiv: Once you create the workflow project, a workflow designer pops up as shown below. Every state in a workflow has events, so go to the workflow toolbox and drag and drop the event driven component on the state activity.
RC: Hang on Shiv, correct me if I am wrong. As per our discussion, logically, every state should have events by which the state changes its action and it should also know which next state it should move to after the event.
Shiv: You are absolutely right. Double click on the state and drag two things: a handle to the external event which defines which event it should listen to, and the set state which says which the next state it should move on to is.
RC: OK great. So how should we define the events and the next state for the state?
Shiv: If you remember, we had defined an interface. It’s time to start using it. Go to the properties of the handle event and select the interface type and the event for it. The below figure shows the state is OrderPlaced and we need to handle the InStock
event.
Shiv: Now to specify the next state, go to the property of the set state component and specify the target state name.
Shiv: So create states, create an event we need to handle in the states, and the next state. You will see that you ended up in something like shown below.
RC: The visuals look great and appealing.
Shiv: Yeah… The most important part for WWF is to get a feel of the workflow development.
RC: OK, this sounds good. What next?
Shiv: One of the most important points we have forgotten is we need to make our concrete class which will be called by the client. Let’s implement the interface IOrder
. You can see the class clsOrder
below which implements IOrder
. We just display simple console messages. Remember, this concrete class will be called by the client and all the below methods of the class will be invoked by the client. This class internally calls the interface which in turn invokes the workflow engine.
public class clsOrder : IOrder
{
#region IOrder Members
public event EventHandler<ExternalDataEventArgs> NotPaid;
public event EventHandler<ExternalDataEventArgs> InStock;
public event EventHandler<ExternalDataEventArgs> PaymentMade;
public event EventHandler<ExternalDataEventArgs> Dispatch;
public event EventHandler<ExternalDataEventArgs> AddressNotProper;
public event EventHandler<ExternalDataEventArgs> AddressCorrected;
public event EventHandler<ExternalDataEventArgs> ProductStocked;
#endregion
public void CallNotPaid(ExternalDataEventArgs args)
{
NotPaid(null, args);
Console.WriteLine("This order is not paid");
}
public void CallInStock(ExternalDataEventArgs args)
{
InStock(null, args);
Console.WriteLine("Product is InStock");
}
public void CallPaymentMade(ExternalDataEventArgs args)
{
PaymentMade(null, args);
Console.WriteLine("Payment is made for this Order");
}
public void CallDispatch(ExternalDataEventArgs args)
{
Dispatch(null, args);
Console.WriteLine("Dispatch the Order");
}
public void CallAddressNotProper(ExternalDataEventArgs args)
{
AddressNotProper(null, args);
Console.WriteLine("Adress is not Proper");
}
public void CallAddressCorrected(ExternalDataEventArgs args)
{
AddressCorrected(null, args);
Console.WriteLine("Adress is corrected");
}
public void CallProductStocked(ExternalDataEventArgs args)
{
ProductStocked(null, args);
Console.WriteLine("Product is stocked");
}
}
RC: Oh OK. So this class will be consumed by the client, right?
Shiv: Yes, that is absolutely right. We need to create the workflow instance using the workflow runtime and start the instance. We also need to add the order class clsorder
object as a service.
WorkflowInstance objWorkFlowInstance;
WorkflowRuntime objWorkFlowRuntime = new WorkflowRuntime();
clsOrder objOrder = new clsOrder();
ExternalDataExchangeService objService = new ExternalDataExchangeService();
Guid InstanceId = Guid.NewGuid();
objWorkFlowRuntime.AddService(objService);
objService.AddService(objOrder);
objWorkFlowInstance = objWorkFlowRuntime.CreateWorkflow(
typeof(OrderWorkFlow.WorkflowOrder), null, InstanceId);
objWorkFlowInstance.Start();
RC: OK, so how will the complete client code look like?
Shiv: Shown below is the code snippet which shows how our client code looks like. What I have done is I take inputs and invoke the workflow methods accordingly.
WorkflowInstance objWorkFlowInstance;
WorkflowRuntime objWorkFlowRuntime = new WorkflowRuntime();
clsOrder objOrder = new clsOrder();
ExternalDataExchangeService objService = new ExternalDataExchangeService();
Guid InstanceId = Guid.NewGuid();
objWorkFlowRuntime.AddService(objService);
objService.AddService(objOrder);
objWorkFlowInstance = objWorkFlowRuntime.CreateWorkflow(
typeof(OrderWorkFlow.WorkflowOrder), null, InstanceId);
objWorkFlowInstance.Start();
Console.WriteLine("Work flow started");
ExternalDataEventArgs objDataEventArgs = new ExternalDataEventArgs(InstanceId);
objDataEventArgs.WaitForIdle = true;
Console.WriteLine("1 - This order is not paid");
Console.WriteLine("2 - Product is InStock");
Console.WriteLine("3 - Payment is made for this Order");
Console.WriteLine("4 - Dispatch the Order");
Console.WriteLine("5 - Adress is not Proper");
Console.WriteLine("6 - Adress is corrected");
Console.WriteLine("7 - Product is stocked");
Console.WriteLine("Enter Appropriate inputs ");
int intValueEntered=0;
while(intValueEntered < 7)
{
intValueEntered = Convert.ToInt16(Console.ReadLine().ToString());
if (intValueEntered == 1)
{
objOrder.CallNotPaid(objDataEventArgs);
}
else if (intValueEntered == 2)
{
objOrder.CallInStock(objDataEventArgs);
}
else if (intValueEntered == 3)
{
objOrder.CallPaymentMade(objDataEventArgs);
}
else if (intValueEntered == 4)
{
objOrder.CallDispatch(objDataEventArgs);
}
else if (intValueEntered == 5)
{
objOrder.CallAddressNotProper(objDataEventArgs);
}
else if (intValueEntered == 6)
{
objOrder.CallAddressCorrected(objDataEventArgs);
}
else if (intValueEntered == 7)
{
objOrder.CallProductStocked(objDataEventArgs);
}
}
RC: OK, let me run it. Great, I can see the order is first placed, then when I enter 2, the product is moved in stock, and when I do dispatch, it moves in to a delivered state.
Shiv: The most important part in the workflow is the workflow logic in your workflow project and your business component are self contained and they do their own activity.
RC: Great man, from where can I download the code? Tonight, I would like to see it when I reach home.
Source code
Shiv: You can find the source code for this article here. In case you are still not clear with workflow basics, you can read WWF.aspx.
For further reading do watch the below interview preparation videos and step by step video series.