While reviewing DinnerNow.net I found an interesting workflow implementation.
A customer place an order for food from multiple restaurants. DinnerNow acts as a hub that will grab the order, will check each item and will group them by restaurant.
How this is implemented? They have two workflows:
- Sequential: this workflow receive a customer order, splits and gorup the order items within a set of restaurant orders. For each restaurant order a state machine workflow is started.
- State machine: this workflow represents a single order workflow (open, ready for pickup, delivered, payed, complete)
You can download DinnerNow today and see this workinf in NET 3.0.
We've been working on some training material lately to show how to do this using NET 3.5. There is a new feature code-named "Silver" (read more on Matt Winkler blog) that basically are a couple of activities to integrate Workflow Foundation with Windows Communication Foundation: the ReceiveActivity and SendActivity.
The following illustration shows how to implement a splitter workflow exposed as a service with WCF:
This workflow is hosted using the new WorkflowServiceHost (that derives from the regular WCF ServiceHost). This new host will read the workflow and will associate the endpoints configured with specific contracts with the workflow implementation.
If you do the analogy with WCF, in WCF you create a service interface and then the implementation with a regular c# class. With Workflow Services you create the interface but the implementation is the workflow itself! And even more easy you can embed the contract metadata in the workflow and the host will read it and associate them with the endpoints.
When a client make a call to the PlaceOrder operation of the IOrderWorkflowService, a new workflow will be started (there is a property in the ReceiveActivity called CanCreateInstance to tell the runtime to do so). This call will be syncrounous but the workflow will start running and will split the orders.
The replicator is similar to a "foreach" statement but it can execute either in sequential or paralel. The first activity that executes is a "SendActivity". This is the counter part of the other activity and will allow calling a service. Either we can call a regular service or we can call another workflow that has a ReceiveActivity listening. And that is what we are doing here: a workflow conversation where the sequential calls the state and when the state finishes it will call the sequential again.
Of course, you will need to somehow manage a context between calls. If not how the workflow knows if you are refering to instance A or instance B.
We are provided with a new set of bindings that allow to do that (netTcpContextBinding and wsHttpContextBinding). This bindings provide a property to access the context:
proxy.PlaceOrder(order); IContextManager cm = proxy.InnerChannel.GetProperty(); IDictionary<XmlQualifiedName, string> context = cm.GetContext();
This context will have the workflow instance id of the recently created workflow. You can add things to the context and read them on the client and the workflow.
IContextManager cm = proxy.InnerChannel.GetProperty(); cm.SetContext(context); proxy.UpdateShipping();
In the case of the child state machine workflow, how do we know which sequential workflow to return after we finish the order process? Simply, we bind the context on the ReceiveActivity of the initial state to a workflow depdendency property. This context is the one sent by the SendActivity of the parent workflow. Then when we get to the complete state we bind the saved context to the SendActivity.