Messaging activities intricacies
WF 4 introduced messaging activities which provides a visual way of creating web services and their clients. In VS 2010 when you do “Add Service Reference” (in a workflow project), the wizard automatically generates activities and config in contrast to imperative code and config (the legacy way J). This looks cool as you can simply drag & drop these activities on a workflow surface and use them to consume your web services. But how does these activities lay themselves on top of WCF ChannelFactory/Channel API?
Send activity is a wrapper around WCF ChannelFactory/Channel API and there is a cache layer built into Send activity’s infrastructure as well. By default, this caching layer is only used in a safe caching mode, where Endpoint information is specified using the properties of Send activity and you are using one of the stock Bindings without any modifications. As soon as you load Binding information from the config (regardless if you have changed the binding or not) safe caching will be disabled.
Without caching, default WSHttpBinding is not suitable for workflow scenarios as it will negotiate credentials (which is a 2 legs handshake) & then establish a secure conversation session (another leg). But then this would be only be used for a single message and needs to be done for every message generated by the Send activity. In my simple example, I have following service which is using default wsHttpBinding and I used VS “Add Service Reference” to generate a client.
The wizard has generated following two activities and along with some default config (default wsHttpBinding)
I then used these activities to craft a basic client which looks like this:
With this simple arrangement my message flow looks this: For Operation1 calls, following 4 infrastructure messages are generated. Note these are request-reply message so each of them has reply message too.
http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue
http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue
http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT
http://tempuri.org/IService/Operation1
http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Cancel
By default, wsHttpBinding is optimized for security and performance – so it establishes a secure conversation which has an upfront cost but applying security for subsequent messages is much cheaper. But unfortunately, in workflow world we only transmit one message as part of secure session, as the second call would use a brand new factory, and all of this will be done again.
Now you can argue here that your binding is still the same default wsHttpBinding binding, why messaging activities didn’t use channel factory caching in this case. As binding information is now coming from the configuration file, messaging activities can’t safely determine that you are using the default binding hence caching is disabled. If you know for sure that you binding is still secure for sharing (as in this case, it was the same default wsHttpBinding) you can enable UnsafeCaching which will then reuse the ChannelFactory for sending messages to the same endpoint. Caching API is exposed via SendMessageChannelCache class, which can be added as an extension into your Workflow Host.
class Program
{
static void Main(string[] args)
{
var invoker = new WorkflowInvoker(new Workflow1());
var cache = new SendMessageChannelCache { AllowUnsafeCaching = true, };
invoker.Extensions.Add(
delegate
{
return cache;
}
);
invoker.Invoke();
cache.Dispose();
}
}
In above example, cache is added as an Instance level cache (notice I’m using Func<> delegate). Cache can be shared at different scopes; Host & AppDomain are the other two options. With above modification you would get the expected behaviour:
Secure conversation session is established at the start and would be used to secure all subsequent messages to the same endpoint.
Remember, you are now getting sessions on the server side and you would have to explicit close those sessions otherwise they will stay hanging and will ultimately saturate your session throttles.
You can close the active sessions by disposing the cache. This will send the Cancel message to the sessions.
http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Cancel
Please note, this is just one example of optimizing the messaging when using workflow services activities.