这里所说的错误处理主要是指服务代码中抛出的异常,即开发人员主动抛出的错误当然,由于网络问题或者配置不正确,会引发连接超时的错误,但这里老周要说的是,我们在实现服务逻辑时主动抛出的异常,尤其是对客户端传入的参数的验证上面。

WCF的异常信息一般会通过 FaultException 类来包装。理论和概念性的东西,大家可以去查资料,老周向来不喜欢谈那些,下面咱们通过实例来了解一下 FaultException。

定义服务协定。

    [ServiceContract(Namespace = "demo-app")]
public interface IOrder
{
[OperationContract]
bool NewOrder(DateTime date, decimal price, long q);
}

假设这个服务的功能是用来下单的,当然不是真的实现下单功能,因为那样太复杂,也不是本文的重点,这里老周安排了三个参数,分别表示下单日期,商品单价,以及商品数量。

下面,咱们来实现一下这个协定。

    internal class OrderSvr : IOrder
{
public bool NewOrder(DateTime date, decimal price, long q)
{
// 验证
if (date < DateTime.Now)
{
throw new ArgumentException("至少要在今天下单");
}
if (price < || q < )
{
throw new ArgumentException("单价或数量不能小于0");
}
// 模拟下单
if ((q * price) == 0.00M)
{
return false;
}
return true;
}
}

正如大伙所看到的,我在实现的服务方法中对参数进行了验证,假设日期早于今天就会抛出异常。

下面是配置文件中的配置信息,这是演示,没什么安全性要求,就使用基本的 HTTP 通信可以了。

  <system.serviceModel>
<services>
<service name="TestApp.OrderSvr">
<endpoint contract="TestApp.IOrder" binding="basicHttpBinding" address="http://127.0.0.1:6035/order"/>
</service>
</services>
<client>
<endpoint name="epcl" contract="TestApp.IOrder" binding="basicHttpBinding" address="http://127.0.0.1:6035/order"/>
</client>
</system.serviceModel>

为了使客户端调用起来舒坦,我还封装一个客户端类(你可以通过服务引用来让VS自动生成,这里为了装逼,我就手动写)。

    public class SampleClient : ClientBase<IOrder>, IOrder
{
public SampleClient() : base("epcl") { } public bool NewOrder(DateTime date, decimal price, long q)
{
return Channel.NewOrder(date, price, q);
}
}

好D,服务的大致功能就是这样,下面我们来调用一下,顺便,咱们传递不符合要求的参数值,看看客户端能否获取到服务器上抛出的异常。

            SampleClient client = new SampleClient();
try
{
bool r = client.NewOrder(date, price, q);
MessageBox.Show(r ? "下单成功。" : "下单失败。");
}
catch(FaultException ftex)
{
MessageBox.Show(ftex.Reason.GetMatchingTranslation().Text);
}
finally
{
client.Close();
}

WCF的异常使用 FaultException 来封装,然后通过 SOAP 消息发回给客户端,所以此处咱们应当捕捉 FaultException 类型的异常。

测试参数如下图所示。

日期晚于今天,符合,但是数量小于0,不符合。故,调用服务后,会看到如下面的高清无码图片所示的异常信息。

噢,your god,大伙发现,没有出现我们想看到的自定义异常信息。

依据上面的提示,可以开启 IncludeExceptionDetailInFaults 选项,有两种方式可以开启该选项,大伙任选其一即可。

1、使用 ServiceBehaviorAttribute,这个特性要应用到实现服务协定的类上,比如,咱们这个示例,服务类是OrderSvr,可以这样来开启:

    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
internal class OrderSvr : IOrder
……

2、如果你不想用代码来设置,可以用配置文件,这样可以方便修改。方法是定义一个service behavior,并添加 serviceDebug 元素。如下

    <behaviors>
<serviceBehaviors>
<behavior name="svbhv">
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>

给它个名字(name),这样方便service元素去引用。

<service name="TestApp.OrderSvr" behaviorConfiguration="svbhv">
……

修改后,再次运行示例,然后输入不正确的参数,就能收到自定义的异常信息了。

         

大伙是不是很是兴奋,终于看到自定义的异常信息了。

================================================

问题似乎已经解决,不过,IncludeExceptionDetailInFaults 选项一般只是在调试阶段开启,正式上线的服务不应该开启,主要为了避免被别有用心的人调戏。所以,开启 IncludeExceptionDetailInFaults 选项还不是最终方案。那还有啥法子呢?

不急,广告回来揭晓……

在服务代码中抛出异常时可以选用 FaultException 类,而且,把一个 FaultReason 对象传给异常。FaultReason 是干吗的?它可以用来封装我们的自定义错误信息,为什么要用它呢,因为它帅?不是,因为一个 FaultReason 实例可以包含一个或N个 FaultReasonText 对象。

FaultReasonText不仅能设置错误描述文本,而且可以与区域/语言关联。比如,你的WCF服务是一个跨生物领域的应用,不仅人可以用,鸟儿、花儿、草儿都可以用,这样你需要返回多种语言版本的错误论处,比如中文的,韩文的,英文的,鸟语的,火星文的,等等。这样,每个 FaultReasonText 就可以封装一个版本的信息。

比如这样:

                FaultReasonText txt1 = new FaultReasonText("我喜欢你", "zh-CN");
FaultReasonText txt2 = new FaultReasonText("I like you", "en-US");
FaultReason reason = new FaultReason(new FaultReasonText[] { txt1, txt2 });

随后,你用这个 FaultReason 对象来 new 一个FaultException实例。

      throw new FaultException(reason);

现在,咱们对服务代码进行修改。

        public bool NewOrder(DateTime date, decimal price, long q)
{
// 验证
if (date < DateTime.Now)
{
FaultReasonText text = new FaultReasonText("至少要在今天下单");
FaultReason reason = new FaultReason(text);
throw new FaultException(reason);
}
if (price < || q < )
{
FaultReason reason = new FaultReason("单价或数量不能小于0");
throw new FaultException(reason);
}
// 模拟下单
if ((q * price) == 0.00M)
{
return false;
}
return true;
}

这里我们只要中文版本就可以了,所以不用弄那么多 FaultReasonText。

在客户端,捕捉到FaultException异常后,要从它的Reason属性中获得 FaultReason 对象,再调用 GetMatchingTranslation 方法来获得错误文本。如果调用的是无参数版本,就按当前语言来获取,你的系统是中文版的,就默认获取中文版错误信息。如果你的系统是鸟文版的,就默认获取鸟文版的错误信息。

            catch(FaultException ftex)
{
MessageBox.Show(ftex.Reason.GetMatchingTranslation().Text);
}

这样修改后,就算 includeExceptionDetailInFaults 选项的值为 false,也能获取到服务器上抛出的错误信息。

顺便提一句,如果WCF示例不能运行,请以管理员身份运行 VS。

好,今天就聊到这里,本文示例下载地址:点这里下载

【WCF】错误处理(一):FaultException 与 FaultReason 的搭配的更多相关文章

  1. WCF初探-20:WCF错误协定

    WCF错误协定概述 在所有托管应用程序中,处理错误由 Exception 对象表示. 在基于 SOAP 的应用程序(如 WCF 应用程序)中,服务方法使用 SOAP 错误消息来传递处理错误信息. SO ...

  2. WCF错误:由于目标计算机积极拒绝,无法连接;127.0.0.1:3456

    问题描述 最近Windows打完补丁,原来部署在本机的WCF无法连接:出现如下WCF错误:由于目标计算机积极拒绝,无法连接:127.0.0.1:3456 解决方案 检查一下本机的服务:NetTcpAc ...

  3. WCF错误处理

    介绍 WCF(Windows Communication Foundation) -异常处理:一般Exception的处理,FaultException和FaultException<T> ...

  4. WCF错误:由于目标计算机积极拒绝,无法连接

    今天学习WCF时用C#重写测试例子时,发生错误:由于目标计算机积极拒绝,无法连接.找了N久,网上也没有找到实际的解决方法.查看netstat -an发现当自承载宿主运行时,没有侦听配置的端口.开始总以 ...

  5. WCF错误:413 Request Entity Too Large

    在我们用WCF传输数据的时候,如果启用默认配置,传输的数据量过大,经常会出这个错误. WCF包含服务端与客户端,所以这个错误可能出现在服务端返回数据给客户端,或客户端传数据给服务端时. 1. 服务端返 ...

  6. WCF错误:413 Request Entity Too Large 的一个解决方法

    在我们用WCF传输数据的时候,如果启用默认配置,传输的数据量过大,经常会出这个WCF:413 Request Entity Too Large的错误. WCF包含服务端与客户端,所以这个错误可能出现在 ...

  7. WCF错误"The maximum message size quota for incoming messages (65536) has been exceeded."

    错误原因有三:超过最大接受的传输值 1.webconfig或者 app.config 文件中的binding 节点进行 配置 maxBufferSize="2147483647" ...

  8. 调用WCF错误-There was no endpoint listening

    问题描述: 今天在调用WCF服务时候出现了下面的错误. 原因: 调用服务的客户端ip设置成了固定ip.(至于固定ip为什么会导致这个错误,没能去研究) 解决方法: 将客户端ip设置成自动获取.

  9. wcf 错误提示

    wcf 不弹出错误提示,只显示“服务器处理请求时遇到错误.有关构造有效服务请求的内容,请参阅服务帮助页”,添加以下节点可以弹出错误提示. <serviceDebug includeExcepti ...

随机推荐

  1. 第六百二十七天 how can I 坚持

    竟然能上google了,可惜手机装twitter装上登不上呢. 浏览浏览能学学英语啊. 今天又在家待了一天,得戒游戏了,找找能让我疯狂的事情,然后坚持去干吧,加油. 洗澡睡觉.

  2. 1.TCP/IP基本概念

    为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣经中上帝打乱了各地人的口音,让他们无法合作一样 ...

  3. eclipse 设置编辑窗口字体和背景颜色

    最近装了几次系统,公司也换过电脑,所以换了几次eclipse,当然家里用的当然是最新版,公司就只有用几百年前的东西了 进入重点,我的编辑窗口习惯使用灰色的背景,感觉全白的不好看,还伤视力(没有科学依据 ...

  4. YII 1.0 设置关联模型

    在model中设置如下 /* * 设置关联 */ public function relations(){ return array( 'cate'=>array(self::BELONGS_T ...

  5. PHP导入导出Excel方法

    看到这篇文章的时候,很是惊讶原作者的耐心,虽然我们在平时用的也 有一些,但没有作者列出来的全,写excel的时候,我用过pear的库,也用过pack压包的头,同样那些利用smarty等作的简单替换xm ...

  6. C++ STL算法系列1---unique , unique_copy函数

     一.unique函数 类属性算法unique的作用是从输入序列中“删除”所有相邻的重复元素. 该算法删除相邻的重复元素,然后重新排列输入范围内的元素,并且返回一个迭代器(容器的长度没变,只是元素顺序 ...

  7. HDU-2573-Typing

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2573 这题把%s与gets()的输入法搞混了一直感觉没有错,就是找不出哪里错了, 题目思路不是很难. ...

  8. RMAN中FILESPERSET设置对备份速度的影响

    看到网上部分人说不指定FILESPERSET(默认值=64)则会导致分配的通道只走第一个而导致备份效率低下,今天仔细研究了一下,参照了多个博主文章,得出结论如下: 如果没有指定filesperset, ...

  9. ubuntu14.04下手动安装eclipse

    ubuntu14.04下手动安装eclipse 第一步: 安装jdk 第二步: 下载eclipse,假设下载的文件文件名为eclipse.tar.gz 第三步: 解压 sudo -zxvf ./ecl ...

  10. ubuntu linux 下 mysql 学习笔记

    '#' 后为注释 以下为在shell中的操作: 打开终端(terminal)1.登录MySQL mysql-u root -p 输入密码:******2.几个简单的命令 (1)show databas ...