Windows Workflow Foundation 异常
工作流可以使用 TryCatch 活动处理工作流执行期间引发的异常。 可以对这些异常进行处理,或者使用 Rethrow 活动重新引发异常。 Finally 节中的活动在 Try 节或 Catches 节完成时执行。 由 WorkflowApplication 实例承载的工作流还可以使用 OnUnhandledException 事件处理程序处理未由 TryCatch 活动处理的异常。
异常的原因
在工作流中,异常可能通过下列方式生成:
TransactionScope 中的事务超时。
工作流通过使用 Throw 活动引发的显式异常。
从活动中引发的 .NET Framework 4.6.1 异常。
外部代码引发的异常,例如工作流中使用的库、组件或服务。
处理异常
如果异常由某个活动引发并且未经处理,则默认行为是终止该工作流实例。 如果存在自定义 OnUnhandledException 处理程序,则它会重写此默认行为。 通过此处理程序,工作流宿主作者能够提供合适的处理操作,例如自定义日志记录、中止工作流、取消工作流或终止工作流。 如果工作流引发未处理的异常,则将调用 OnUnhandledException 处理程序。 从 OnUnhandledException 返回了三个可能的操作,确定工作流的最后结果。
取消 - 取消的工作流实例是分支执行的正常退出。 可以对取消行为进行建模(例如,通过使用 CancellationScope 活动进行建模)。 取消进程完成时,将调用“已完成”处理程序。 已取消的工作流处于“已取消”状态。
终止 - 已终止的工作流实例无法继续执行或重新启动。 这会触发“已完成”事件,并且可以提供相应的异常来表明终止的原因。 终止进程完成时,将调用“已终止”处理程序。 终止的工作流处于“已出错”状态。
中止 - 已中止的工作流实例只有在配置为持久化的情况下,才可以继续执行。 如果未配置持久性,则工作流无法继续执行。 在工作流中止的时间点上,自上次持久性点以来的所有已完成工作(内存中)都将丢失。 对于已中止的工作流,在中止进程结束时将调用“已中止”处理程序,并且使用相应的异常来表明中止的原因。 不过,与已取消和已终止不同,已中止的工作流不会调用“已完成”处理程序。 中止的工作流处于“已中止”状态。
下面的示例调用了引发异常的工作流。 工作流未处理异常,并且 OnUnhandledException 处理程序已被调用。 将检查 WorkflowApplicationUnhandledExceptionEventArgs 以提供有关异常的信息,且终止工作流。
Activity wf = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Starting the workflow."
},
new Throw
{
Exception = new InArgument<Exception>((env) =>
new ApplicationException("Something unexpected happened."))
},
new WriteLine
{
Text = "Ending the workflow."
}
}
};
WorkflowApplication wfApp = new WorkflowApplication(wf);
wfApp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
{
// Display the unhandled exception.
Console.WriteLine("OnUnhandledException in Workflow {0}\n{1}",
e.InstanceId, e.UnhandledException.Message);
Console.WriteLine("ExceptionSource: {0} - {1}",
e.ExceptionSource.DisplayName, e.ExceptionSourceInstanceId);
// Instruct the runtime to terminate the workflow.
return UnhandledExceptionAction.Terminate;
// Other choices are UnhandledExceptionAction.Abort and
// UnhandledExceptionAction.Cancel
};
wfApp.Run();
使用 TryCatch 活动处理异常
在工作流内部处理异常是通过 TryCatch 活动执行的。 TryCatch 活动带有 Catches 活动的 Catch 集合,其中每个活动都与一个特定的 Exception 类型关联。 如果 Try 活动的 TryCatch 节中包含的活动引发的异常与 Catch<TException> 集合中 Catches 活动的异常匹配,则处理该异常。 如果此异常再次显式引发,或者引发了新异常,则此异常将向上传递到父活动。 下面的代码示例演示处理 TryCatch 的 ApplicationException 活动,该异常由 Try 活动在 Throw 节中引发。 异常的消息由 Catch<TException> 活动写入控制台,然后在 Finally 节中将一条消息写入控制台。
DelegateInArgument<ApplicationException> ex = new DelegateInArgument<ApplicationException>()
{
Name = "ex"
};
Activity wf = new TryCatch
{
Try = new Throw()
{
Exception = new InArgument<Exception>((env) => new ApplicationException("An ApplicationException was thrown."))
},
Catches =
{
new Catch<ApplicationException>
{
Action = new ActivityAction<ApplicationException>
{
Argument = ex,
Handler = new WriteLine()
{
Text = new InArgument<string>((env) => ex.Get(env).Message)
}
}
}
},
Finally = new WriteLine()
{
Text = "Executing in Finally."
}
};
Finally 节中的活动在 Try 节或 Catches 节成功完成时执行。 如果未从中引发任何异常,则 Try 节成功完成;如果未从中引发或重新引发任何异常,则 Catches 节成功完成。 如果在 Try 的 TryCatch 节中引发了异常,并且未由 Catch<TException> 节中的 Catches 处理或是从 Catches 重新引发,将不执行 Finally 中的活动,除非出现下列情况之一。
异常未由更高级别的 TryCatch 进行处理,并且排除了工作流的根,此时工作流将配置为取消而不是终止或中止。 使用 WorkflowApplication 承载的工作流可以通过处理 OnUnhandledException 和返回 Cancel 来对此进行配置。 在本主题的前面提供了处理 OnUnhandledException 的示例。 工作流服务可以通过使用 WorkflowUnhandledExceptionBehavior 并指定 Cancel 来对此进行配置。 有关配置 WorkflowUnhandledExceptionBehavior 的示例,请参阅工作流服务主机可扩展性。
异常处理与补偿
异常处理与补偿的不同之处在于:异常处理是在活动的执行期间发生的, 而补偿在活动成功完成后发生。 通过异常处理,可以在活动引发异常之后进行清理,而补偿提供了一种机制,可用于撤消以前完成的活动中所成功完成的工作。 有关详细信息,请参阅补偿。