分享
 
 
 

正确捕获 WCF服务调用中发生的异常及处理技巧

王朝学院·作者佚名  2010-01-15
窄屏简体版  字體: |||超大  

概述:本节主要讲述在服务调用中可能发生的异常及模拟异常的发生,并分析何时可捕获何种异常,以及如何把服务异常以正确的方式传递到客户端,

文章最后给出正确捕获异常的捕获顺序。本次异常捕获仅为介绍,部分为应用性功能,所以代码和行文相对简单,还介绍了在服务器端异常处理的一些技巧。

1、 首先,我们创建一个简单的计算器服务器和客户端,如下:

点击展开代码

//服务器[ServiceContract]public interface ICalc{[OperationContract][FaultContract(typeof(GreentingError))]string Div(int x, int y);}public class Calc : ServiceBase, ICalc {public string Div(int x, int y) {string result = string.Empty; try {result = string.Format("result: {0}", x / y); } catch (DivideByZeroException ex) {throw ex; }return result; }}//客户端[ServiceContract] public interface ICalc { [OperationContract] [FaultContract(typeof(GreentingError))] string Div(int x, int y); }public class CalcClient : ClientBase<ICalc>, ICalc{ public string Div(int x, int y) {return base.Channel.Div(x, y); }}

好吧,我承认代码相当的简单,不过我喜欢简洁的东西。

2、 简单的东西就是好,调用都简单得多;我们来调用一下。

try { CalcClientcalcclient = new CalcClient(); string result =calcclient.Div(10, 0); Console.WriteLine(result); Console.ReadKey(); } catch (TimeoutExceptionex) {throw ex; } catch (FaultException<GreentingError> ex) {throw ex; } catch (FaultExceptionex) {throw ex; catch (System.ServiceModel.CommunicationException ex) {throw ex; } catch (Exceptionex) {throw ex; }

3、当我们在调用服务的Div(int x,int y)方法并给对数y传递了值为0后,服务器端将会引发DivideByZeroException的异常,这在预料之中。这时候,

在客户端的FaultException部分捕获了这个异常。

4、没问题,我们再在服务器代码中手动抛出FaultException异常。

catch (DivideByZeroException ex){FaultException exception = new FaultException(ex.Message); throw exception;}

这时候发现,还是FaultException捕获了这个异常,为何?

5、再做一个测试。

在服务加入这句代码:System.Threading.Thread.Sleep(70000);使得服务超时。

这回终于是TimeOutException捕获了服务器的异常,那么我们就要问了,FaultException< GreentingError>何时会捕获异常呢?答案是当服务器抛出FaultException< GreentingError>的时候,引用MSDN上的一段话(绿色部分):

如果侦听器接收到操作协定中不期望或未指定的 SOAP 错误,将会引发 FaultException对象, 可以发送两种类型的 SOAP 错误:已声明的和未声明的。 已声明的 SOAP 错误是指其中的某个操作具有System.ServiceModel.FaultContractAttribute属性(用于指定自定义 SOAP 错误类型)的错误。 未声明的 SOAP 错误是在操作的协定中没有指定的错误。这里的“不期望或未指定的 SOAP 错误”是指未在服务操作中应用FaultContractAttribute包装的自定义错误类型。

6、那么何时会捕获CommincationException异常呢?

MSDN上说是:应用程序处理在通信期间可能会引发的 CommunicationException 对象

好吧,为了引发这个异常,我们来作如下操作。首先在服务器关闭当前通道对象。

OperationContext.Current.Channel.Close();

很遗憾,客户端并没有捕获到CommunicationException,而是捕获到了TimeOutException异常!因为服务通道关闭后,并未发生异常,所以没有返回消息到客户端,客户端在等待一定时间后,超时退出。

所以我们在关闭通道的同时指定一个TimeSpan。这样可以让调用立即返回,当然,还可以通过Channel.Abort来完成调用返回。

OperationContext.Current.Channel.Close(new TimeSpan(5000));

在调用了IContextChannel的Close方法的同时,指定在超时前必须完成发送操作的时间,这样可以使得消息在指定时间内立即返回,而不必等到服务调用超时,否则到时客户端必将引发TimeOutException异常,而不是CommunicationException异常。

7、补救措施

同时,为了在服务出现异常时我们可以采取一些补救的措施,我们新建了一个抽象类ServiceBase,并使得Calc服务实现类继承自它,这样我们就可以在服务各种状态转换中取得控制权。ServiceBase类如下:

public abstract partial class ServiceBase { private IContextChannel channel = null; protected ServiceBase() { channel = OperationContext.Current.Channel; channel.Opening += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }); channel.Opened += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }); channel.Closing += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }); channel.Closed += new EventHandler(delegate(object sender, EventArgs e) { Abort(); }); channel.Faulted += new EventHandler(delegate(object sender, EventArgs e) { Abort(); }); } void Open() {/* TO DO*/ } void Close() { /* TO DO*/} void Abort() { channel.Abort(); }}

从上面的代码中可以看出,在服务通道关闭以后,我们立即将服务中止,让消息立即返回,这时候即使在操作中关闭了服务而又未指定超时完成的时间,调用依然可以立即返回。

这次客户端总算捕获到了CommunicationException异常,见下图:

为何会这样?

8、让我们来看一下CommunicationException的继承层次,从中我们可以得到启示。

8.1、首先是FaultException<TDetail>的继承层次。

8.2、再次是TimeOutException的继承层次。

9、从上图中可以看出,TimeOutException和CommunicationException均继承自SystemException类,而FaultException继承自CommunicationException,最后是FaultException<TDetail>继承自FaultException类。

10、最后我们得出,在客户端正确的捕获异常的顺序应该是:

TimeOutException> FaultException<TDetail> > FaultException >CommunicationException > Exception。在这里强烈建议开发人员抛出和捕获FaultException<TDetail>类型的异常。

作者:老米

出处:http://www.cnblogs.com/viter/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有