One of the most powerful aspects of Windows Workflow is that it can manage a workflow instance's state when it has no work to do. Obviously to do this it needs to know that your activity is waiting for something to happen. A number of activities in the Standard Activity Library run asynchronously like this -e.g. the DelayActivity and the new ReceiveActivity. However, most real WF projects require you to write your own custom activities. To perform long running operations or wait for external events to occur, these too should be able to run asynchronously.
To be usable in all situations, an async activity needs to do more than just derive from Activity and return ActivityExecutionStatus.Executing from the Execute override. It also needs to implement IActivityEventListener<QueueEventArgs> and IEventActivity (the latter allows it to be recognised as an event driven activity). We end up with 3 interesting methods
Execute
IEventActivity.Subscribe
IEventActivity.Unsubscribe
Depending where your activity is used these get called in a different order
Sequential Workflow: Execute
State Machine: Subscribe, Execute, Unsubscribe
ListenActivity: Subscribe, Unsubscribe, Execute
So getting the behavior correct in where you create the workflow queue you are going to listen on, set up the event handler on the queue, process the results from the queue and close the activity can be a little tricky. So I have created a base class for async activities that buries the complexity of the plumbing and leaves you with three responsiblities:
- Tell the base class the name of the queue you wish to wait on
- Optionally override a method to set up any infrastructure you need before you start waiting on the queue
- Override a method to process the data that was passed on to the queue and decide whether you are still waiting for more data or you are finished
You can download the code here AsyncActivityBaseClass.zip (38.36 KB). Any feedback gratefully received
Finally, thanks to Josh and Christian for sanity checking the code