Long running workflows and the ReceiveActivity

Using a ReceiveActivity is a great way of exposing a workflow via a WCF proxy.

Get started by creating a new project based upon “Sequential Workflow Service Library”. This is found in the WCF projects node instead of the Worflow projects node!

Create a service interface, mine is nice and simple and add a few ReceiveActivity to the workflow and hoop up the service interface to the activities. No big deal so far and we can test things by just pressing F5 and having the WCF Test Client. Actually you can only call functions that are hooked up to an ReceiveActivity with the CanCreateInstance set to True so the WCF Test Client might not be all that useful here if you use multiple ReceiveActivity that are part of a single workflow or conversation.

Next step is to create a simple console application as a client with the following code:


Sub SimpleDemo()


Dim proxy As
New ServiceReference1.DoStuffClient

Console.WriteLine(proxy.AskQuestion(“Is this cool?”))

proxy.AllDone()


End
Sub

 

This code works just fine [:)] until we decide to split it up and recreate the WCF proxy object for part two like this [:(]:


Private
Sub Part1()


Dim proxy As
New ServiceReference1.DoStuffClient

proxy.GetStarted(“Maurice”)

Console.WriteLine(proxy.AskQuestion(“To be or not to be?”))


End
Sub

 


Private
Sub Part2()


Dim proxy As
New ServiceReference1.DoStuffClient

Console.WriteLine(proxy.AskQuestion(“Is this cool?”))

proxy.AllDone()


End
Sub

 

In this case the second proxy object doesn’t work at all and we get a FaultException with the message “There is no context attached to incoming message for the service and the current operation is not marked with “CanCreateInstance = true”. In order to communicate with this service check whether the incoming binding supports the context protocol and has a valid context initialized.”

So what gives? Well the WCF service needs to know which workflow the request needs to be routed to and uses the WorkflowInstanceId to do so. When you create a proxu and do the first call this WorkflowInstanceId is automatically added and resent with the next request. So we need to retrieve this WorkflowInstanceId and, when we create the second proxy object, add it again. Doing so turns out to be pretty simple and only takes a few extra lines of code:


Private _instanceId As
String

 


Private
Sub Part1()


Dim proxy As
New ServiceReference1.DoStuffClient

proxy.GetStarted(“Maurice”)


Dim contextManager As IContextManager = _

proxy.InnerChannel.GetProperty(Of IContextManager)()


Dim context As Dictionary(Of
String, String) = _

contextManager.GetContext()

_instanceId = context(“instanceId”)

Console.WriteLine(proxy.AskQuestion(“To be or not to be?”))


End
Sub

 


Private
Sub Part2()


Dim proxy As
New ServiceReference1.DoStuffClient


Dim contextManager As IContextManager = _

proxy.InnerChannel.GetProperty(Of IContextManager)()


Dim context As
New Dictionary(Of
String, String)

context.Add(“instanceId”, _instanceId)

contextManager.SetContext(context)

Console.WriteLine(proxy.AskQuestion(“Is this cool?”))

proxy.AllDone()


End
Sub

 

Basically what we need to do is retrieve the workflow instanceId from the context that is returned with the first call and save that. Next time we create a new proxy object we need to store the same instanceId in the request context before we actually use it and we are good to go [:)] Setting the instaceId is actually done through a ClientContextProtocol object which is returned as an IContextManager inside of the channel properties. Check the bold lines in the previous code sample.

So why is this so important?

Well one of the most powerful features of Workflow Foundation is its capability to have long running workflows. Now long running workflows would not be very useful if the client application needs to keep its proxy alive for as long as it need to communicate with the workflow. Guess that would make “long running” a very relative thing. But with this technique all the client has to do is save the workflow instanceId somewhere, perhaps a database table, and it can reconnect to the same workflow at a later point in time.

Enjoy!

3 thoughts on “Long running workflows and the ReceiveActivity

Leave a Reply

Your email address will not be published. Required fields are marked *


*