As a follow up to my previous post, I’ve been extending my implementation a bit. In the comments section of my last post you might have read that we were thinking about creating a CorrelationSequenceActivity. I’ve implemented this activity now and it currently accepts only one child activity which should be a ReceiveActivity. This is validated using an activity validator. It has an attached property called CorrelationKey which will then appear on the ReceiveActivity. You can bind this property to whatever you want in you’re workflow. Then when the CorrelationSequenceActivity is executed it registers the correlation key together with the instance ID of the workflow to a runtime service that implements IWorkflowCorrelationRuntimeService. When the CorrelationSequenceActivity is being closed it will automatically unregister the correlation key. We might have to extend this further in the future in order to support a scenario where the workflow is waiting for two events in parallel, each with their own correlation key, but that is not a scenario that we foresee right now.
Building the CorrelationSequenceActivity was quite easy, although I ran into a few problems with the attached property. It isn’t as straight forward as using the DependencyProperty.RegisterAttached method. You’ll have to implement the IExtenderProvider interface and do all kinds of fancy stuff with designers. Luckily there’s already some documentation on how this all works which you can find right here.
So how does this IWorkflowCorrelationRuntimeService interface work? Well, it has three operations, RegisterCorrelationKey, UnregisterCorrelationKey and LookupInstanceIdForCorrelationKey. The first two operations are called by the CorrelationSequenceActivity. The last one is called by the WorkflowCorrelationInstanceContextProvider I talked about in my previous post. So this should take care of correlating the correlation key that was extracted from the incoming message to the right workflow instance. It doesn’t solve the extraction of the correlation key from the input message, but it should be theoretically possible to give the CorrelationSequenceActivity another attached property with a designer where you can select a property from the input message and which would then create an XPath query that extracts the key from the input message automagically. As we only have one service operation where we need to do correlation this isn’t much of an issue for us right now.
Obviously the IWorkflowCorrelationRuntimeService interface allows for some extensibility. The WorkflowCorrelationEndpointBehavior from my previous post will try to get the configured one from the workflow runtime and if it doesn’t find one it will insert a memory based one. This just works with an internal dictionary where the correlation keys and instance ID’s are stored. I’ve also created a SqlWorkflowCorrelationRuntimeService that stores the correlation keys and their associated instance ID’s into an extra table in the workflow persistence & tracking store. It implements IPendingWork so it participates in any transaction as needed. This doesn’t work correctly when combined with the SharedConnectionWorkflowCommitWorkBatchService, but that’s another story.
The only thing I haven’t implemented yet is the IEventActivity interface as my colleague Robert suggested. It shouldn’t be too hard to implement this though, but we won’t need it just yet.