Fault Handling in Workflows
Fault handling in Windows Workflow Foundation refers to the handling of exceptions in an asynchronous manner. This means that exceptions that are thrown in an activity (explicitly or implicitly) are caught by the workflow runtime engine and then scheduled in a queue to be handled at a later time. This differs from normal exception handling in that if an exception is thrown in a try block, it is either caught by the appropriate catch exception block, or it is thrown to the user immediately.
Causes of Exceptions
In a workflow, exceptions can be generated in the following ways:
A time-out of transactions in TransactionScopeActivity or CompensatableTransactionScopeActivity.
An explicit exception thrown by the workflow using the ThrowActivity activity. For more information, see Using the ThrowActivity Activity.
A .NET Framework exception thrown from the handlers of the code activity or code-beside of custom activities.
An exception thrown from external code, such as libraries or components that are used in the workflow.
In fault handling, if the activity that threw the exception cannot handle it, the exception is transferred to its parent activity for resolution. The exception is transferred up the workflow hierarchy until it is either handled, or the workflow instance is terminated by the workflow runtime engine.
Handling the exception is done by the FaultHandlerActivity activity. Each FaultHandlerActivity activity is associated with the .NET Framework exception type and further contains a set of activities that are executed if the exception raised matches the exception type. A FaultHandlerActivity activity is parented in a FaultHandlersActivity activity that contains 0-n FaultHandlerActivity activities. The FaultHandlersActivity activity can be a child activity of any composite activity.
The goal of fault handling in Windows Workflow Foundation is to undo the partial and unsuccessful work of an activity in which an exception has occurred. The completion of the FaultHandlerActivity activity is never considered a successful completion of its associated activity. This means that while the FaultHandlerActivity activity is executing, the activity that threw the exception is put into a faulting state. When the FaultHandlerActivity activity has completed, the associated activity is put into the closed state. Also, any sibling activities of that associated activity, such as other children of a ParallelActivity activity, are placed into a canceling state, and then into the closed state. They are never given the chance to successfully execute.
Fault Handling versus Compensation
The difference between fault handling and compensation is that compensation can only be performed on an activity that has successfully completed, not one that has thrown an exception and is in a faulting state; however, the CompensateActivity activity can be executed inside a FaultHandlerActivity activity that is associated with an activity that has thrown an exception. For example, a typical scenario for compensation handling would be when an activity successfully completes, but an exception is thrown in another activity later in the workflow. The fault handler for that activity contains a CompensateActivity that reverses any actions previously done in the workflow. To expand on this further, you might refund a customer their money after an ItemDiscontinuedException is thrown later in your workflow by another activity.
For more information about compensation handling, see Using the CompensateActivity Activity.