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 活动的异常匹配,则处理该异常。 如果此异常再次显式引发,或者引发了新异常,则此异常将向上传递到父活动。 下面的代码示例演示处理 TryCatchApplicationException 活动,该异常由 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 节成功完成。 如果在 TryTryCatch 节中引发了异常,并且未由 Catch<TException> 节中的 Catches 处理或是从 Catches 重新引发,将不执行 Finally 中的活动,除非出现下列情况之一。

异常处理与补偿

异常处理与补偿的不同之处在于:异常处理是在活动的执行期间发生的, 而补偿在活动成功完成后发生。 通过异常处理,可以在活动引发异常之后进行清理,而补偿提供了一种机制,可用于撤消以前完成的活动中所成功完成的工作。 有关详细信息,请参阅补偿

另请参阅