本文目的 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
通过阅读本文,您能理解以下的知识 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
1) WCF中存在哪几种异常处理方式?øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
2) 各种异常处理所适用的应用场合? øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
3) WCF中常见的异常类型? øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
4) 代码不骗人,用示例来演示效果,加深印象 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
本文适合的读者 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
本文适合WCF的初学者,但要求对WCF有一些了解,并实现过简单的服务/客户端。 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
WCF中存在哪几种异常处理方式?
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
WCF定义了几种异常处理模型,它们分别如下: øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
1) 缺省模式 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
2) 包含详细信息模式 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
3) 自定义异常消息模式 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
各种异常处理所适用的应用场合? øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
1) 缺省模式 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
缺省情况下,服务端发生异常,客户端会得到一个缺省的Exception,但这个Exception实例中并不包括详细的异常信息。只是告诉客户端服务端不能正常工作。在服务器和客户端模式的程序中,有些情况下,服务启是不能完全信赖客户端的,比如浏览器和web服务器之间,为了防止非法的客户端从异常消息中获取服务端的比较详细的信息,使得心怀叵测之人有机可乘,所以服务启对于异常返回通常会比较模糊。WCF也采用了这种做法,缺省情况下,它返回给客户端的异常只告知我出错了,但不告诉人家他哪里错了。这通常应用于客户端来源不明的生产环境,以此保护服务程序。 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
2) 包含详细信息模式 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
如果想消息更友好一些,可以通过IncludeExceptionDetailInFaults=True来设置返回具体的异常信息,这样就能告诉客户端服务出错了,并指出错误出在哪里。在程序开发阶段或者有些应用场合,客户端是受信任的,为了让客户端能更详尽的了解服务端到底出了什么问题,WCF也支持发送详细的错误消息给客户端,这更有利于应用程序调试。而返回详细异常有两种方法:第一种:通过在服务端的配置文件中设置:<serviceDebugincludeExcepti/>,第二种方式为通过在代码中指定:[ServiceBehavior(IncludeExceptionDetailInFaults=true)] øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
3) 自定义异常消息模式 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
在WCF中,还支持更详细的异常消息,它通过自定义的异常消息FaultMessage来传达更多的内容。WCF采用通用的SoapFault来处理异常,并提供了FaultException和FaultException<FaultMessage>两个类型来描述和操作异常。 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
WCF中常见的异常类型? øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
WCF包括三种常见类型的异常: øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
1) 通讯异常,这通常是因为链路的原因,比如服务没有启动,网络阻塞等。这类异常是CommunicationException或者其派生类 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
2) 状态异常,这类异常通常是与上文提到的实例模式相关的,当访问了一个已经销毁的服务器对象时便会引发此类型的异常,它们通常是ObjectDisposedExceptionøÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
3) 服务异常,由服务端根据具体的业务逻辑触发,通常是FaultException 值得注意的是当抛出服务异常的时候,不同的实例模式的处理方式有所不同: øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
PerSession:这种模式下,抛出异常,服务实例将销毁,客户端抛出FaultException,客户端代理对象无法继续使用 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
PerCall:这种模式下,抛出异常,服务实例也将销毁。客户端代理对象无法继续使用 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
Single:这种模式下,抛出异常,服务实例会照旧运行。客户端代理无法继续使用。 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
代码不骗人,用示例来演示效果,加深印象 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
本文所实现的实例非常简单,目的就是想验证一下各种异常处理方式下的不同表现。 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
1) 缺省模式 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
在示例中,我们这样抛出异常 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
publicøÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
string GetWelcomeInfo([ParaAtt(CanSetNull=false)] string name) øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
{ øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
ParameterInfo para
= MethodInfo.GetCurrentMethod().GetParameters()[0]; øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
ParaAtt att
= ParaAtt.GetCustomAttribute(para, typeof(ParaAtt)) as ParaAtt; øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
if (!att.CanSetNull && name ==øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
null) øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
{ øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
throwøÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
new Exception("参数不能设置为null"); øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
}
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
returnøÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
"Hello,"øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
+ name; øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
}
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
而此时,我们运行客户端,可以发现如下的运行结果: øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
从结果可以看出,缺省情况下,虽然客户端跑出了异常,但这些异常消息是不呈献给客户端的 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
2) 包含详细信息模式 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
将服务端配置文件中的<serviceDebug includeExcepti />,再次启动,此时客户端不但能收到和上图一致的跟踪堆栈信息,不同的是异常消息也会呈现给客户端 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
3)  自定义异常消息模式 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
这种模式是异常处理中相对最难的,因为它更加灵活,我们首先定义一个用于表示错误消息的数据契约ExceptionMsg,如下: øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
using System; øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
using System.Collections.Generic; øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
using System.Linq; øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
using System.Text; øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
using System.Runtime.Serialization; øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
namespace Jillzhang.Wcf.ExContracts øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
{ øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
[DataContract] øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
publicøÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
class ExceptionMsg øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
{ øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
/**////øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
<summary> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
/// 异常消息文本 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
///øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
</summary>øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
[DataMember] øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
publicøÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
string Message { get; set; } øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
/**////øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
<summary> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
/// 异常编码 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
///øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
</summary>øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
[DataMember] øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
publicøÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
string ErrorCode { get; set; } øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
}
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
}
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
在定义操作的时候,我们可以指定返回的异常消息的类型,方法如下: øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
[OperationContract] øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
[FaultContract(
typeof(ExceptionMsg))] øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
int Devide(int x, int y); øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
运行实例程序,可以得到如下的结果: øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
我们可以用tcpTrace来跟踪下异常消息,有关如何跟踪WCF的Soap消息,前面文章WCF从理论到实践二:决战紫禁之巅øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
有所描述。本文讲述例外一种方法用于跟踪basicHttpBinding,为此我们要准备一款工具,TraceUtility,它是Microsoft SOAP Toolkit Version3中的一个工具,利用它可以清晰地看到SoapMessage,方式如下:打开Trace Utility,选择菜单项File-FormatedTrace,在接下来的对话框中填写要监听的端口和服务的端口,如下图所示:
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
点击确定后,将原来客户端端中的服务地址由 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
更改为 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
启动,便可以在Trace Utility中跟踪到SoapMessage,如下: øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
- <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
-
<s:Body> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
-
<s:Fault> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
<faultcode>s:Client</faultcode> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
<faultstring xml:lang="zh-CN">The creator of this fault did not specify a Reason.</faultstring> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
-
<detail> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
-
<ExceptionMsg xmlns="http://schemas.datacontract.org/2004/07/Jillzhang.Wcf.ExContracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
<ErrorCode>001</ErrorCode> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
<Message>除数不能为0</Message> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
</ExceptionMsg> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
</detail> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
</s:Fault> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
</s:Body> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
</s:Envelope> øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
另外很多人不清楚如何调试跟踪WCF应用程序,特别是想从客户段跟踪到服务中,可以通过以下步骤来完成: øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
本文参考资料 øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
本文示例项目: øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
/Files/jillzhang/Jillzhang.Wcf.ExceptionHandler.rarøÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø
øÕc:Êg°ðÍwww.netcsharp.cn¥3³á¢íÔø