1问题描述
工作流和宿主程序通讯的时候,经常碰到一下异常:
{"无法为实例 ID“c083a3ea-96e5-4bd2-bb9c-da2049244e08”传递接口类型“Mjgforever.Workflow.LocalServices.IOrderManagement”上的事件“OrderShipped”。"}
出现这种情况的时候,我们经常查阅msdn或去网上搜索,出现各种各样的答案,然后去试各种解决方案,这种方式很浪费时间。为什么呢?这是因为没有找到本质原因。
2 问题剖析
在书写程序的时候,我们经常这样捕获异常:
try
{
if (eh != null)
{
OrderEventArgs e = new OrderEventArgs(workflowId, orderInfo);
e.WaitForIdle = true; //设置是立即引发事件还是工作流在引发前处于空闲状态
eh(this, e);
}
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(">>> RaiseEvent Error: " + ex.Message + " <<<");
eventResult = false;
}
这样写有什么问题吗?一个致命的问题是可能不能捕获真正的异常!在这一点上,还是喜欢eclipse开发环境,它会提示我们要处理哪些异常,不知道微软什么时候推出这种功能。另外,大家有什么好办法可以可能的异常,最好带提示性质的,毕竟每个类或函数引发的异常都去查的话,很费时,最后的解决方案就用Exception全代替了。在这点上,希望哪位高手指点一下。
这里就要讲讲Exception的InnerException 属性。该属性表示获取导致当前异常的 Exception 实例。通过这个进行追踪,我们可以找到真正的引发异常的原因。
3 InnerException介绍
属性值
类型:System..::.Exception
一个 Exception 实例,它描述导致当前异常的错误。InnerException 属性返回与传递给构造函数的值相同的值,或者,如果没有向构造函数提供内部异常值,则返回 null 引用(Visual Basic 中为 Nothing)。此属性为只读。
备注
当异常 X 作为以前的异常 Y 的直接结果发生时,X 的 InnerException 属性应当包含对 Y 的引用。
使用 InnerException 属性获得导致当前异常的异常集。
您可以创建对以前的异常进行捕捉的新异常。处理第二个异常的代码可利用前一个异常的其他信息更适当地处理错误。
假定有一个可以读取文件并格式化该文件中数据的函数。在此示例中,当代码试图读取文件时引发 IOException。该函数捕捉 IOException 并引发 FileNotFoundException。IOException 可以保存在 FileNotFoundException 的 InnerException 属性中,从而使捕捉 FileNotFoundException 的代码可以检查导致初始错误的原因。
保存对内部异常引用的 InnerException 属性在初始化异常对象时设置。
下面的例子,大家可以试验一下。
using System;
public class MyAppException : ApplicationException
{
public MyAppException(String message)
: base(message)
{ }
public MyAppException(String message, Exception inner) : base(message, inner) { }
}
public class ExceptExample
{
public void ThrowInner()
{
throw new MyAppException("ExceptExample inner exception");
}
public void CatchInner()
{
try
{
this.ThrowInner();
}
catch (Exception e)
{
throw new MyAppException("Error caused by trying ThrowInner.", e);
}
}
}
public class Test
{
public static void Main()
{
ExceptExample testInstance = new ExceptExample();
try
{
testInstance.CatchInner();
}
catch (Exception e)
{
Console.WriteLine("In Main catch block. Caught: {0}", e.Message);
Console.WriteLine("Inner Exception is {0}", e.InnerException);
}
}
}
4 实例分析
实例一:
{"无法为实例 ID“c083a3ea-96e5-4bd2-bb9c-da2049244e08”传递接口类型“Mjgforever.Workflow.LocalServices.IOrderManagement”上的事件“OrderShipped”。"}
InnerException属性异常信息:
未启用队列“Message Properties
Interface Type:Mjgforever.Workflow.LocalServices.IOrderManagement
Method Name:OrderShipped
CorrelationValues:
”。
解决方案:这时只需要将代码中注释部分去掉就可以解决问题了。(e.WaitForIdle=true)
实例二
{"无法为实例 ID“c083a3ea-96e5-4bd2-bb9c-da2049244e08”传递接口类型“Mjgforever.Workflow.LocalServices.IOrderManagement”上的事件“OrderShipped”。"}
InnerException属性异常信息:
程序集“OrderLocalServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”中的类型“Mjgforever.Workflow.LocalServices.OrderManagementService”未标记为可序列化。
5 小结
写这篇文章主要向大家说明两点:
(1)通过try … catch(Exception ex) { ex.Message};不一定能真正找到异常。我们要查找InnerException,直到该属性为null。通过InnerException属性定位真正的异常。
(2)vs在异常捕获上,没有eclipse好用,不知道大家有没有好的解决方案,这样我们在捕获异常的时候可以很快的定位。如下所示,我们在捕获IO异常的时候,有时会这样写。Eclipse就会建议我们写,vs好像没有这样的功能。
catch(FileNotFoundException fnfe)
{
}
catch(IOException ioe)
{
}
catch(Exception ex)
{
}
最后,希望这篇文章能帮助大家迅速地查找错误的原因,避免漫无目的的搜素、求助,自己就可以搞定。
参考文献
Msdn