Yesterday I posted a long blog post explaining how to do duplex communications in a Workflow service. Its a long story but the most important points where that workflow services don’t support the same style duplex communication as WCF with the callback channel defined in the ServiceContract but rather something that is called durable duplex where the callback contract is independent and the client has to create a ServiceHost and act as a full-blown WCF service. Also the callback address had to be passed by the client using CallbackContextMessageProperty and the workflow service had to use a callback correlation handle to connect the Receive activity with the Send activity used for the callback.
So what is the problem with using the CallbackContextMessageProperty and CorrelationHandle?
There is no real problem per se except that it takes quite a bit of doing to set this up, both on the client and in the workflow service. Because standard WCF callbacks are not supported by workflow services using a ServiceHost to handle the callback on the client is unavoidable. This is unfortunate because this prevents several scenarios, most notably, using Silverlight for the client application. However all the complexity with the CallbackContextMessageProperty and CorrelationHandle is only there to pass a single string, the callback address. And the Send activity has the capability to set the callback address dynamically using the EndpointAddress property.
Would it not be much simpler in this case to pass the callback address as a parameter to our initial service call?
As it turns out it is! And in the rest of this post I will show how to do just that.
The starting point is the DuplexDemo solution from the previous post. You can download this code from here.
First thing is to add a string variable “callbackAddress” and update the Receive activity to accept this as a second parameter.
And we need to set the Send activity EndpointAddress to the passed address using “New Uri(callbackAddress)”
Next we can remove the callbackHandle we no longer need. Remove this from the variables, the Receive CorrelationInitializers and the Send activity CorrelatesWith. That is the service done. Next we need to remove some code from the client removing the OperationContextScope, CallbackContextMessageProperty and adding the callback address as the second parameter to the GetData() call. The code in the Main() function now looks like this:
static void Main(string[] args)
{
var address = "http://localhost:8080/ServiceCallback";
var serviceCallback = new ServiceCallback();
var host = new ServiceHost(serviceCallback, new Uri(address));
host.Open();
var proxy = new ServiceClient();
Console.WriteLine(proxy.GetData(42, address));
Console.ReadLine();
proxy.Close();
host.Close();
}
So much simpler [:)]
But besides being simpler there is another benefit. Because the callback address is being passed as a normal piece of data instead of some hidden context header we can check if it is passed. So we can have our workflow check if a callback address is passed and if not just skip the callback altogether. This way the workflow service is still usable from clients, like Silverlight, where creating a ServiceHost is not an option. Of course they don’t receive the data being passed in the callback so that is something to keep in mind when deigning your workflow.
Conclusion.
I like the simpler approach this offers. It doesn’t mean that durable duplex should never be used, it certainly has its place, but when this simpler approach is all that is needed so much the better.
Sample project SimpleDuplexDemo.zip
Enjoy!
www.TheProblemSolver.nl
Wiki.WindowsWorkflowFoundation.eu