对于C#程序中抛出的异常我们可以使用try-catch来捕获并处理。在WF中的对异常的处理和C#中也比较相似,不过有一些不同,主要有以下几点:
1. WF中一个未处理的异常仅仅会让当前的工作流实例终止而不会导致整个应用程序终止,并且会触发WorkflowRuntime的WorkflowTerminated事件。
2. WF中的异常处理是异步的,所以WF可以将未处理的异常放在内部队列中等待处理。
3. WF中的异常可以使用代码方式处理,也可以在WF模型中处理。我们使用FaultHandlerActivity活动,该活动就像C#中的catch语句一样,每个FaultHandlerActivity活动对应一个异常类型,该活动为复合活动,我们可以添加子活动来编写自己的逻辑处理程序.
如果在一个工作流中发生异常,他会先检查自身有没有捕获异常,如有没有会检查他的父活动有没有捕获,如果直到工作流的根活动都没有捕获异常,那么整个工作流就终止了,这时会引发WorkflowRuntime的WorkflowTerminated事件。
未处理的异常
1.我们下面举例来说明,首先我们建立一个顺序工作流控制台项目CaryExceptionDemo,新建一个顺序型工作流ExWorkflow,我们放两个CodeActivity.在CodeActivity1中我们根据workflow传入的参数抛出两个异常。具体代码如下:
public sealed partial class ExWorkflow: SequentialWorkflowActivity { private int number; public int Number { get { return number; } set { number = value; } } public ExWorkflow() { InitializeComponent(); } private void codeActivity1_ExecuteCode(object sender, EventArgs e) {
switch (Number) { case 1: throw new DivideByZeroException("DivideByZeroError"); case 2: throw new ArithmeticException("ArithmeticError"); default:break; } } private void codeActivity2_ExecuteCode(object sender, EventArgs e) { Console.WriteLine("第二个CodeActivity执行了"); } } 2.对这两个异常我们不去捕获,他会使工作流终止触发WorkflowRuntime的WorkflowTerminated事件,宿主程序的代码
如下:
class Program { static void Main(string[] args) { using(WorkflowRuntime workflowRuntime = new WorkflowRuntime()) { AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waitHandle.Set(); }; workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine("工作流终止:" + e.Exception.Message); waitHandle.Set(); }; Dictionary<String, Object> wfParas = new Dictionary<string, object>(); wfParas.Add("Number", 1); Dictionary<String, Object> wfParas1 = new Dictionary<string, object>(); wfParas1.Add("Number", 2); Console.WriteLine("---开始执行第一个工作流---"); WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(CaryExceptionDemo.ExWorkflow), wfParas); instance.Start(); waitHandle.WaitOne(); Console.WriteLine("---第一个工作流执行结束---"); Console.WriteLine();
Console.WriteLine("---开始执行第二个工作流---"); WorkflowInstance instance1 = workflowRuntime.CreateWorkflow(typeof(CaryExceptionDemo.ExWorkflow), wfParas1); instance1.Start(); waitHandle.WaitOne(); Console.WriteLine("---第二个工作流执行结束---"); } }
}
3.执行的结果为在WorkflowTerminated中输出相关信息如下表,我们发现CodeActivity2活动并没有执行,正是由于
CodeActivity1抛出的异常导致工作流终止。
---开始执行第一个工作流--- ---开始执行第二个工作流--- |
使用FaultHandlerActivity捕获异常
1.我们下面捕获并处理CodeActivity1抛出的两个异常,我们在工作流的错误处理试图中使用FaultHandlerActivity活动来捕获异常,如下图所示:
2.我们在faultHandlersActivity1中拖入两个FaultHandlerActivity活动,将他们的FaultType属性分别设置为System.DivideByZeroException和System.ArithmeticException,这里有一点要注意那就是这两个活动的左右次序不能反了,处理DivideByZeroException一定要在左边,这就像我们C#中的Catch一样先处理特定的异常,在处理一般的异常。在FaultHandlerActivity的中我们放我们自己的处理异常代码,如下:
private void codeWFHandle_ExecuteCode(object sender, EventArgs e) { FaultHandlerActivity faultActivity = ((Activity)sender).Parent as FaultHandlerActivity; String message = String.Empty; if (faultActivity != null) { message = faultActivity.Fault.Message; } Console.WriteLine("处理算术异常: {0}", message); }
运行该工作流得到如下结果:
---开始执行第一个工作流--- ---开始执行第二个工作流--- |
在活动中捕获异常
我们从上面的结果中发现工作流中CodeActivity2依然没有执行,这主要是因为当异常发生的时候会自动寻找合适的FaultHandlerActivity来处理,由于我们在工作流级别捕获的异常自然CodeActivity2就没有执行,有点时候这不是我们想要的结果,如何来达到我们的目的呢,其实很简单,我们让CodeActivity1在一个容器中执行,我们使用该容器的错误处理试图来捕获异常并处理,在WF中只有实现的Activity组件,才有FaultHandlersActivity异常捕获容器。SequenceActivity就可以实现,工作流设计如下图:
在sequenceActivity1的错误处理视图中我们只需要将原来放在工作流错误处理视图中的两个FaultHandlerActivity剪切过来就可以了。现在我们运行程序得到结果如下:
---开始执行第一个工作流--- ---开始执行第二个工作流--- |
从结果中我们可以CodeActivity2活动执行了。这些是WF中关于异常处理的一些知识。