Update: 6/24 – updated sample to show how unhandled exceptions and the UnhandledException delegate impact this activity
Nearly a year ago I created a CancellationScope Activity sample and posted it on CodeGallery for .NET 4 Beta 1. I went back yesterday and updated it for .NET 4 RTM – the sample has some interesting points to demonstrate.
It shows how the CancellationScope Activity works but it also shows
- How to create a custom activity that causes the workflow to go idle for testing purposes
- How to create a unit test that verifies the behavior of a console application by simply verifying the text output to the console.
You can download the sample from http://code.msdn.microsoft.com/wf4CancellationScope
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.
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 WorkflowApplication.Cancel or by returning UnhandledExceptionAction.Cancel from the UnhandledException delegate.
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?
It depends on what the host application does in response to an unhandled exception.
|UnhandledExceptionAction||Cancel Handler Invoked||Notes|
|Abort (default)||No||Workflow aborts WorkflowApplication.Aborted delegate is invoked|
|Cancel||Yes||The workflow is canceled as though WorkflowApplication.Cancel() were invoked|
|Terminate||No||Specifies that the System.Activities.WorkflowInstance should schedule termination of the root activity and resume execution.|
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
In this example you can observe the behavior of nested cancellation.
When it starts you enter a number between 1 and 4 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.
If you enter scope level 4 it will throw an unhandled exception so you can see how the workflow behaves when this occurs.
Try It Out
Download the sample code from the Downloads tab. (This sample requires Visual Studio 2010 / .NET 4)
- Explore the sample, check out program.cs and CancellationScop.xaml
- Press Ctrl+F5 to compile and run the sample
- 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).
- To see what happens when you have an unhandled exception thrown in the cancel handler, try level 3.
- To see what happens when you throw an unhandled exception from the body of the CancellationScope, try level 4.
Test It Out
This sample also includes a unit test project CancelScope.Tests that you can study to see how we tested this sample application