坚持学习WF(24):WF中的异常处理

简介:

[置顶]坚持学习WF文章索引

对于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抛出的异常导致工作流终止。

---开始执行第一个工作流--- 
工作流终止:DivideByZeroError 
---第一个工作流执行结束---

---开始执行第二个工作流--- 
工作流终止:ArithmeticError 
---第二个工作流执行结束--- 
请按任意键继续. . .

 

使用FaultHandlerActivity捕获异常

1.我们下面捕获并处理CodeActivity1抛出的两个异常,我们在工作流的错误处理试图中使用FaultHandlerActivity活动来捕获异常,如下图所示:

wfex1

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);
}

运行该工作流得到如下结果:

---开始执行第一个工作流--- 
处理除0异常: 除0异常 
---第一个工作流执行结束---

---开始执行第二个工作流--- 
处理算术异常: 算术异常 
---第二个工作流执行结束--- 
请按任意键继续. . .

 

在活动中捕获异常

我们从上面的结果中发现工作流中CodeActivity2依然没有执行,这主要是因为当异常发生的时候会自动寻找合适的FaultHandlerActivity来处理,由于我们在工作流级别捕获的异常自然CodeActivity2就没有执行,有点时候这不是我们想要的结果,如何来达到我们的目的呢,其实很简单,我们让CodeActivity1在一个容器中执行,我们使用该容器的错误处理试图来捕获异常并处理,在WF中只有实现的Activity组件,才有FaultHandlersActivity异常捕获容器。SequenceActivity就可以实现,工作流设计如下图:

wfex2

在sequenceActivity1的错误处理视图中我们只需要将原来放在工作流错误处理视图中的两个FaultHandlerActivity剪切过来就可以了。现在我们运行程序得到结果如下:

---开始执行第一个工作流--- 
处理除0异常: 除0异常 
第二个CodeActivity执行了 
---第一个工作流执行结束---

---开始执行第二个工作流--- 
处理算术异常: 算术异常 
第二个CodeActivity执行了 
---第二个工作流执行结束--- 
请按任意键继续. . .

从结果中我们可以CodeActivity2活动执行了。这些是WF中关于异常处理的一些知识。



本文转自生鱼片博客园博客,原文链接:http://www.cnblogs.com/carysun/archive/2008/10/18/WFException.html,如需转载请自行联系原作者

相关文章
|
存储 设计模式 前端开发
Streamlit应用中构建多页面(三):两种方案(上)
Streamlit应用中构建多页面(三):两种方案
4085 0
|
小程序 前端开发
保健品商城小程序模板源码
保健品商城小程序模板源码
1037 3
|
监控 关系型数据库 MySQL
银河麒麟V10 SP3 X86 二进制文件部署 mysql-5.7.29 GTID 半同步复制的双主架构
银河麒麟V10 SP3 X86 二进制文件部署 mysql-5.7.29 GTID 半同步复制的双主架构
868 1
|
关系型数据库 MySQL Spring
mysql 默认八小时空闲自动断开连接
MySQL 的默认设置下,当一个连接的空闲时间超过8小时后,MySQL 就会断开该连接,而 c3p0 连接池则以为该被断开的连接依然有效。在这种情况下,如果客户端代码向 c3p0 连接池请求连接的话,连接池就会把已经失效的连接返回给客户端,客户端在使用该失效连接的时候即抛出异常 解决这个问题的办法有三种: 1. 增加 MySQL 的 wait_timeout 属性的值。 修改 /et
3494 0
|
消息中间件 监控 Kafka
深入理解 Kafka 集群搭建与管理
Apache Kafka 作为分布式流处理平台的核心,其集群搭建与管理是确保高可用性和高性能的关键。本文将深入研究 Kafka 集群的构建、配置、工作原理、节点角色以及一些高级管理策略,以助力大家更深层次地理解和灵活运用 Kafka 集群。
Java——多线程高并发系列之ReadWriteLock读写锁
Java——多线程高并发系列之ReadWriteLock读写锁
774 3
Java——多线程高并发系列之ReadWriteLock读写锁
|
安全 应用服务中间件 Linux
IO多路转接(三)
IO多路转接
169 0
|
存储 SQL Java
一个精美的登录界面原来是这样做的
一个精美的登录界面原来是这样做的
408 0
|
消息中间件 SQL 运维
开发之痛:稳定的测试环境,怎么就那么难 | 研发效能提升36计
开发之痛:稳定的测试环境,怎么就那么难。对于生产环境,准确、稳定最重要,我们推荐以应用为中心的基于OAM和IaC的实践方式;对于测试环境,隔离、低成本和稳定的依赖是最重要的,我们推荐基于稳定环境的隔离测试环境的实践,复用稳定环境,通过流量隔离和数据隔离来生成测试环境。通过环境建设,我们解决了研发过程中的资源冲突。
1564 1
开发之痛:稳定的测试环境,怎么就那么难 | 研发效能提升36计