Processing WorkflowRuntime Events
The Windows Workflow runtime engine raises several events throughout its lifetime that your host application can handle. These consist of events that notify your application when the runtime engine is Started or Stopped, and also several events that correspond to the lifetime of any running workflow instances. The procedure to create event handlers for these events follows the same event-handling pattern provided in the .NET Framework. As an example, the following code creates an event handler for the Started event raised by the workflow runtime when it begins execution.
AddHandler workflowRuntime.Started, AddressOf OnWorkflowStarted
...
Shared Sub OnWorkflowStarted(ByVal sender As Object, ByVal e As WorkflowRuntimeEventArgs)
Console.WriteLine("WorkflowRuntime started")
End Sub
workflowRuntime.Started += delegate(object sender, WorkflowRuntimeEventArgs e)
{
Console.WriteLine("WorkflowRuntime started");
};
The following table lists the events that can be raised by the Windows Workflow runtime engine that pertain to the workflow runtime engine itself.
Event | Description |
---|---|
Raised when a service that is derived from the WorkflowRuntimeService abstract class calls the RaiseServicesExceptionNotHandledEvent method, because an exception occurs during workflow execution that the service cannot handle. |
|
Started |
Raised when the workflow runtime engine starts running. |
Stopped |
Raised when the workflow runtime engine stops running. |
The following table lists the workflow instance events that can be raised by the workflow runtime engine.
Event | Description | ||
---|---|---|---|
Raised when a workflow is stopped in the middle of processing. |
|||
Raised when a workflow completes processing. |
|||
Raised when a workflow is instantiated. |
|||
Raised when a workflow enters the idle state. |
|||
Raised when a workflow is recreated from a storage medium. |
|||
Raised when the current state of the workflow is persisted to a storage medium. |
|||
Raised when a workflow resumes executing after it has been stopped or unloaded. |
|||
Raised when a workflow starts running. |
|||
Raised when a workflow enters the suspended state. |
|||
Raised when a workflow is terminated. |
|||
Raised when a workflow is unloaded. |
WorkflowAbort Conditions
There are several different conditions that can occur during the execution of a workflow that can raise the WorkflowAborted event. For example, a host application can intervene in the process by calling the Abort method from a WorkflowInstance object. In this case, the reason is known and the logic to handle this can easily be created in the host application itself.
There are conditions however when the Windows Workflow Foundation runtime engine will abort a workflow. An example of this condition is a result of the runtime engine failing to terminate a workflow instance. A common scenario related to this condition concerns the SqlWorkflowPersistenceService. If the workflow runtime engine needs to terminate a workflow and the SqlWorkflowPersistenceService is active, the runtime engine will attempt to persist the workflow state. However, if a SqlException is thrown during the persistence operation, the runtime engine will have to abort the workflow instance. When this occurs, you can use a TrackingService to dump the exception information in order to debug the scenario that caused the runtime engine to abort the workflow instance.
Determining Workflow Terminated Source
The WorkflowTerminated event can be raised either programmatically through the host application, by using a TerminateActivity in a workflow or as a result of an uncaught exception. If your host application needs to perform certain logic based on the type of action that caused the workflow to terminate, there are several key pieces of logic you will need to check. The following table shows different states of a workflow and where to look for information regarding the reason for termination.
Action | Workflow Status | Activity Execution Status | Terminate or Suspend Info |
---|---|---|---|
Normal Execution |
Completed |
Closed |
NULL |
TerminateActivity (Reason specified and not NULL) |
Terminated |
Executing |
Reason specified in Workflow design |
TerminateActivity (Reason is NULL) |
Terminated |
Executing |
Exception of type Workflow Terminated was thrown |
Terminated from host application |
Terminated |
Executing |
Reason specified in Terminate method parameter |
Unhandled Exception |
Terminated |
Closed |
Message of the Exception causing the termination |
Unhandled Exception in Fault Handler |
Terminated |
Closed |
Message of the Exception causing the termination |
The location in the workflow where an exception was thrown can be found by walking the workflow graph and checking the status of each Activity at the time of the termination. The following code demonstrates how to accomplish this if the exception is thrown from a FaultHandlerActivity.
Private Function isExceptionfromFaultHandler(ByVal rootActivity As Activity) As Boolean
If rootActivity Is Nothing Then
Return False
End If
If TypeOf rootActivity Is CompositeActivity Then
If TypeOf rootActivity Is FaultHandlersActivity Then
If rootActivity.ExecutionStatus = ActivityExecutionStatus.Closed Then
Return True
End If
End If
For Each act As Activity In (CType(rootActivity, CompositeActivity)).Activities
If isExceptionfromFaultHandler(act) Then
Return True
End If
Next
End If
Return False
End Function
bool isExceptionfromFaultHandler(Activity rootActivity)
{
if (rootActivity == null)
return false;
if (rootActivity is CompositeActivity)
{
if (rootActivity is FaultHandlersActivity)
{
if (rootActivity.ExecutionStatus == ActivityExecutionStatus.Closed)
return true;
}
foreach (Activity act in ((CompositeActivity)rootActivity).Activities)
if (isExceptionfromFaultHandler(act))
return true;
}
return false;
}