CancellationScope Activity

Last Edit: 2-Jun-2009

How do you cancel work in your application?  Many middle tier components and services rely on transactions to handle cancellation for them.  This makes a great deal of sense because transactional programming is well understood.  However there are many times when you must cancel work that cannot be done under a transaction.  Cancellation can be very difficult because you have to track work that has been done to know how to cancel it.  WF4 also includes compensation activities that can be used to do clean up work as well.

Windows Workflow Foundation 4 helps you with this by providing a CancellationScope activity. 

Cancellation Scope 1

In today’s example I’m going to show you how you can use a cancellation scope to manage cleanup work.

How does cancellation happen?

Before we consider how the CancellationScope, let’s think about how cancellation happens in a workflow.  There are 2 ways it can happen, from inside of a workflow or from the outside.  Child workflow activities are scheduled by their parent activity (such as a Sequence, Parallel, Flowchart or some custom activity).  The parent activity can decide to cancel child activities for any reason.  For example, a Parallel activity with three child branches will cancel the remaining child branches whenever it completes a branch and the  CompletionCondition expression evaluates to true.

The workflow can also be cancelled from the outside by the host application by calling the Cancel method on the WorkflowInstance.

How does the cancellation scope work?

It’s very simple really, the cancellation scope has a Body.  This is where you do the work that you might have to cancel later.  The CancelHandler contains the activities you want to run if the activity is canceled. 

Does an unhandled exception cause the cancellation handler to be invoked?

No it does not.  Unhandled exceptions cause the workflow to abort, cancellation handlers are not invoked.

What if my cancellation handler throws an unhandled exception?

If you have an unhandled exception in the cancellation handler the workflow will immediately terminate with the exception.  This is similar to throwing an exception from within a catch block.

Show me a sample

I created some sample code for this blog post that cancels the workflow from the outside.  In this example you can observe the behavior of nested cancellation.

When it starts you enter a number between 1 and 3 to determine the number of nested levels you want to call.  When you get to the limit of that level the workflow will call a custom activity I created call GoIdle that simply sets a bookmark.  This will cause the workflow to become idle and the WorkflowInstance.OnIdle handler will be invoked handing control back to the host.

In program.cs I’ve created two AutoResetEvents, one that will be signaled when the workflow goes idle and another that will be signaled when the workflow completes or terminates with an exception.  This is a little unusual but I know that my workflow will go idle when it matches one of the nesting levels 1,2 or 3.

Try It Out

Download the sample code from here.  (This sample requires Visual Studio 2010 / .NET 4 Beta 1)

  1. Explore the sample, check out program.cs and Sequence1.xaml
  2. Press Ctrl+F5 to compile and run the sample
  3. When it prompts you for a level try level 1 or 2.  You will see that cancellation happens in reverse order of invocation (level 2 cancels before level 1).
  4. To see what happens when you have an unhandled exception thrown in the cancel handler, try level 3.

CancelCmd