WCF基础教程之异常处理:你的Try..Catch语句真的能捕获到异常吗?
在上一篇WCF基础教程之开篇:创建、测试和调用WCF博客中,我们简单的介绍了如何创建一个WCF服务并调用这个服务。其实,上一篇博客主要是为了今天这篇博客做铺垫,考虑到网上大多数WCF教程都是从基础讲起的,大家平时工作可能只是去调用和修改WCF的一些方法,而并未创建和配置过WCF,如果大家通过网上的教程去一步一步的创建和配置WCF,中途遇到错误,特别是WCF的配置这块很容易出错,难免会浪费时间。今天,我们就主要来说一下WCF中服务端和客户端的异常处理。
接着昨天的例子,我们在UserService中添加一个新的方法,或者直接修改DoWork方法,抛出一个异常,代码如下:
[OperationContract]
public void GetMessage()
{
throw new Exception("System Error!");
}
下面,我们在客户端调用这个方法,代码如下:
public void GetData()
{
UserServiceReference.UserServiceClient client = new UserServiceReference.UserServiceClient();
client.GetMessageCompleted += client_GetMessageCompleted;
client.GetMessageAsync();
} void client_GetMessageCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if(e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
}
这里值得注意的是,在异步方法执行完成后,参数e会携带WCF抛出的异常信息,保存在e.Error中。下面我们按下F5,来执行看看会发生什么,如图:
首先我们看到的是VS在WCF服务端捕获到了异常,因为我们用的是Debug模式,这里可以看到详细的异常信息,“System Error”,按F5继续走,会看到如下图:
到这里,我们看到已经到了客户端,已经看不到异常详细了,继续按F5,向后走,看到弹出如下消息框,如图:
看到这个异常信息,完全不知道WCF哪里出现错了,对于修复Bug的程序员来说无疑是一个噩梦。
从上面的实例演示中,我们可以获知WCF在默认情况下的异常处理行为:对于服务端抛出的异常(这里主要指应用异常),客户端捕获到的总一个具有相同异常消息。由于异常类型和消息固定不变,对于服务的客户端来说,直接通过捕获到的异常相关的信息是无法确定服务端在执行服务操作的时候遇到的具体的错误是什么。
根据微软MSDN的文档:https://msdn.microsoft.com/zh-cn/library/dd470096(VS.95).aspx,在web项目中添加SilverlightFaultBehavior类,其代码如下:
public class SilverlightFaultBehavior : Attribute, IServiceBehavior
{
private class SilverlightFaultEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
} public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
} public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new SilverlightFaultMessageInspector());
} public void Validate(ServiceEndpoint endpoint)
{
} private class SilverlightFaultMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
} public void BeforeSendReply(ref Message reply, object correlationState)
{
if ((reply != null) && reply.IsFault)
{
HttpResponseMessageProperty property = new HttpResponseMessageProperty();
property.StatusCode = HttpStatusCode.OK;
reply.Properties[HttpResponseMessageProperty.Name] = property;
}
}
}
} public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
} public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
{
endpoint.Behaviors.Add(new SilverlightFaultEndpointBehavior());
}
} public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
然后,修改UserService的代码如下:
然后,我们在UserService上面,点击鼠标右键,在浏览器中预览一下,然后再客户端上的UserServiceReference上面,点击右键,更新服务引用,然后我们按Ctrl + F5,以release模式运行项目(这样不会中断),如图:
我们看到,这次显示了不同的错误,但是依然没有抛出真正的异常信息,我们还是不知道哪里出现错了。不过根据提示消息,我们可以看到解决办法,然后打开webConfig,寻找includeExceptionDetailInFaults,果然有这个配置,如图:
我们修改includeExceptionDetailInFaults的值为true,然后再执行,我们看到了如下信息:
哈哈,终于看到真正的异常信息了。
下面再来说一种方法,不修改webconfig文件,如图:
当然,我们也可以完整的将WCF的异常的抛给客户端(服务端不做任何错误处理),但是这样可能会泄露一些敏感信息,并不安全。更多关于WCF异常处理的信息,可以参考园内大牛的博客:
下面,我们修改客户端代码,添加一个代理类,来对WCF的调用进行一些封装,关于WCF中使用回调函数,可以参考我之前的这篇博客Silverlight中异步调用WCF服务,传入回调函数,代码如下:
这里客户端的异常e.Error可以通过回调函数传递给页面,然后做处理。然后,我们修改UserService,如图:
然后,更新服务引用,我们调用这个WCF方法,加上Try...Catch...,大概就变成了下面这个样子,如图:
这时我们按下F5运行,会看到弹出了我们返回的结果:"WCF Result"。
下面我们在显示结果前加些代码,如图:
然后,F5运行,猜猜会出现什么情况,按照我们所想的,应该是弹出一个消息框,对吧,但是,实际情况是这样的,如图:
咦,为什么我们写的Try...Catch...没有捕获到异常呢?代码明明在Try...Catch...里面啊~~,到这里,我想你们应该清楚我这边博客标题的含义了吧~~
如果之前一直是这样的写的,以后就要赶紧改啦~~
其实,我们出现异常的这段代码,是通过一个Lamda表达式传进来的一个匿名委托,相当于一个独立的方法,所以这个方法根本就不在你的Try...Catch...的作用域内。(说的不对,还请指正)。
所以,将Try...Catch...写到内部就可以了,修改代码如下,就可以了,如图:
到这里,就算是说完了。这里提醒一下大家以后写代码,测试的时候一定要下断点全部走到,特别是异常处理部分。最后,祝大家工作愉快,欢迎加入QQ交流群,一起学习交流。
作者:雲霏霏
QQ交流群:243633526
博客地址:http://www.cnblogs.com/yunfeifei/
声明:本博客原创文字只代表本人工作中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未授权,贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文连接。
如果大家感觉我的博文对大家有帮助,请推荐支持一把,给我写作的动力。
WCF基础教程之异常处理:你的Try..Catch语句真的能捕获到异常吗?的更多相关文章
- WCF基础教程——vs2013创建wcf应用程序
引言 近期在项目中见到了师哥们常常谈到的WCF这方面的知识.当时在写程序的时候也没有理解wcf究竟是个什么东西? 以及我们为什么在项目中会採用这种框架来实现,仅仅是依照师哥他们写好的代码编写同样格 ...
- WCF基础教程之开篇:创建、测试和调用WCF
一转眼,又半个月没有更新博客了.说实话,最近确实是有点忙.不过即使再忙忙,也要抽空来学习一些东西.最近用WCF比较多,就来跟大家分享一下关于WCF的知识吧!为了让大家都能看懂,照顾一些没有学过WCF的 ...
- 纯手写wcf代码,wcf入门,wcf基础教程
1.定义服务协定 =>定义接口 using System.ServiceModel; namespace WcfConsole { /// <summary> /// 定义服 ...
- Python学习入门基础教程(learning Python)--3.2 if-else分支语句
if-else分支语句结构的特点是当conditon条件满足时,执行if下的语句块,当condition条件不满足时执行else下的语句块,也就是说根据条件来控制让某些语句执行,某些语句不被执行. i ...
- Java基础__Java中异常处理那些事
一.Exception 类的层次 所有的异常类是从 java.lang.Exception 类继承的子类. Exception 类是 Throwable 类的子类.除了Exception类外,Thro ...
- C++基础知识:异常处理
1.C++中的异常处理(1)C++ 中提供了 try和catch语句块对可能产生异常的代码进行分开处理 -try语句块处理正常逻辑 -catch语句块处理异常(2)C++ 语言中通过 throw语 ...
- Java基础教程——异常处理详解
异常处理 好程序的特性 可重用性 可维护性 可扩展性 鲁棒性 |--|--Robust的音译 |--|--健壮.强壮之意 |--|--指在异常和危险情况下系统依然能运行,不崩溃 Java中,写下如下代 ...
- WCF开发教程资源收集
WCF开发教程资源收集 1.蒋金楠,网名Artech的博客 [原创]我的WCF之旅(1):创建一个简单的WCF程序[原创]我的WCF之旅(2):Endpoint Overview[原创]我的WCF之旅 ...
- WCF基础
初入职场,开始接触C#,开始接触WCF,那么从头开始学习吧,边学边补充. SOA Service-Oriented Architecture,面向服务架构,粗粒度.开放式.松耦合的服务结构,将应用程序 ...
随机推荐
- 云计算P2V的迁移过程
总结一下客户在传统物理机向虚拟化环境迁移中的典型场景和常用工具及步骤.
- 【转】Nginx服务器详细配置含注释
#使用的用户和组 user www www; #指定工作衍生进程数(一般等于CPU的总核数或总核数的两倍) worker_processes 8; #指定错误日志存放的路径,错误日志的记录级别可为de ...
- $(function(){})、$(document).ready(function(){})....../ ready和onload的区别
1.window.onload 当一个文档完全下载到浏览器中时,会触发 window.onload 事件. 这意味着页面上的全部元素对 javascript 而言都是可以访问的,这种情况对编写功能性的 ...
- ROS BY EXAMPLE 1 -- 环境设置与安装
rbx1 package 的环境设置: sudo apt-get install ros-indigo-turtlebot-bringup \ ros-indigo-turtlebot-create- ...
- 解决mac安装grunt时出现[command not found]的错误
第一步: 1先确定一下.bash_profile是否存在. 2在mac终端输入: test -e .bash_profile && echo "found" || ...
- Python处理json格式的数据文件(一些坑、一些疑惑)
这里主要说最近遇到的一个问题,不过目前只是换了一种思路先解决了,脑子里仍然有疑惑,只能怪自己太菜. 最近要把以前爬的数据用一下了,先简单的过滤一下,以前用scrapy存数据的时候为了省事也为了用一下它 ...
- while语句(1)
<?php for ($i=1; $i<=10 ; $i++) { echo $i."-".($i*10)."<br>&q ...
- g++编译选项
-g,生成供调试用的可执行文件,可以在gdb中运行.由于文件中包含了调试信息因此运行效率很低,且文件也大不少. -c:生成名为source_file.o的目标文件. -o, 指定输出文件名,可以配合以 ...
- backbone框架思路
Backbone是MVC框架.如何使用这个框架来简化前端过程呢?作为一个初学者,虽然网上有它的官方文档,但是都是讲的一些方法,思路分析的却对初学者来说,看得晕乎乎的.现在就把自己对这个框架的理解记录在 ...
- 搜索引擎 ElasticSearch 之 步步为营 【主目录】
ElasticSearch 是一款著名的分布式搜索引擎框架,采用Java编写.具有搜索速度快,实时搜索等特色. 以下为官网对ElasticSearch的介绍: Elasticsearch 是一款高可伸 ...