【WCF】错误协定声明

时间:2021-12-08 00:30:37

在上一篇烂文中,老周给大伙伴们介绍了 IErrorHandler 接口的使用,今天,老周补充一个错误处理的知识点——错误协定。

错误协定与IErrorHandler接口不同,大伙伴们应该记得,上回我们是把自己实现IErrorHandler接口的类型添加到ChannelDispatcher中的,也就是说,IErrorHandler处理的是通道层的错误,它可以捕捉到多个服务操作上发生的错误。而错误协定是面向协定层的,它是通过 FaultContractAttribute 来声明的,这个特性在上一篇文章中我们用过,它应用的目标是方法。故而这个特性是针对某个服务操作而定义的,主要指明在某个服务操作可能会引发的  FaultException<TDetail> 异常,其中的TDetail泛型参数的类型是在FaultContract特性中指定。

在上一篇烂文中提到过,如果是像string、int这些基本类型,是可以直接用的,如果是自定义的类型,则应该将其声明为数据协定,然后在FaultContract特性中作声明。

咱们来实战一下。首先,咱们定一个服务协定。

    [ServiceContract(Namespace = "zhou-demo", Name = "runner")]
public interface IDemo
{
[OperationContract(Action = "getNum", ReplyAction = "getNumRes")]
[FaultContract(typeof(ErrorData), Namespace = "zhou-demo/faults", Name = "fault-ct", Action = "fault-back")]
int GetNumber();
}

这个协定没什么重要的事情干,无非就是返回一个整数,待会儿咱们让它返回随机整数。

不过大家注意,我在方法上应用了FaultContract特性,它的构造函数是个Type,这个Type用来指定存放错误详细信息的类型,这个类型就是FaultException<TDetail>中的TDetail的类型。其他属性如Action,Namespace、Name这些,不用我多说了吧,都知道干吗用的,你也可以不设置的,它会自动生成一个默认值。

ErrorData是我自己定义的一个数据协定,请看下面代码。

    [DataContract(Namespace = "zhou-demo/fault-data")]
public class ErrorData
{
[DataMember]
public int ErrorNumber { get; set; }
[DataMember]
public string ErrorSource { get; set; }
[DataMember]
public string ErrorMessage { get; set; }
[DataMember]
public string ErrorType { get; set; }
}

这个好懂吧,不必介绍了吧。

当服务操作中发生异常时,可以用ErrorData类来封装自定义的错误信息,WCF会把它序列化,然后塞进SOAP消息中发回给客户端,客户端就可以catch到这些错误数据了。

接下来,实现服务类。

    class DemoService : IDemo
{
public int GetNumber()
{
Random rand = new Random();
int n = rand.Next();
if(n % == )
{
ErrorData erdata = new ErrorData
{
ErrorNumber = n,
ErrorSource="人品",
ErrorType="生物机能错误",
ErrorMessage ="运气指数不佳,引发不可修复错误。"
};
throw new FaultException<ErrorData>(erdata);
}
return n;
}
}

这代码没什么技术含量,你如果看不懂,应该写一份30万字的检讨书。随机生成一个整数,如果这个整数可以被3整除,那就抛出异常,否则正常返回这个数值。

服务完成,下面该轮到实例化ServiceHost了,有了Host我们才能调用服务。Host的处理很TMD简单,直接指定:基址 + 服务类型 = 完事。

            Uri baseAddress = new Uri("http://localhost:9973");
ServiceHost host = new ServiceHost(typeof(DemoService), baseAddress);
host.Open();
Console.WriteLine("服务已启动。");
……
host.Close();

还记得老周以前说过吧,如果仅仅指定基址,而不定义任何EndPoint的话,Host会自动根据协定个数和基址个数,自动生成默认的终结点。在这个高大上例子中,基址是http方案的,所以生成的终结点默认使用BasicHttpBinding,由于服务类只实现了一个服务协定接口,所以该Host中也就只有一个终结点了。

好了,万事具备,只欠东风了,东风就是客户端调用代码。

            Console.WriteLine("请按 Esc 键退出,按任意键调用服务。");
ConsoleKeyInfo keyinfo;
while((keyinfo = Console.ReadKey(true)).Key != ConsoleKey.Escape)
{
EndpointAddress epaddr = new EndpointAddress(baseAddress);
BasicHttpBinding binding = new BasicHttpBinding();
IDemo channel = ChannelFactory<IDemo>.CreateChannel(binding, epaddr);
try
{
int x = channel.GetNumber();
Console.WriteLine($"\n调用结果:{x}。");
}
catch(FaultException<ErrorData> ftex)
{
ErrorData detail = ftex.Detail;
string msg = $"\n错误数字:{detail.ErrorNumber}\n" +
$"错误源:{detail.ErrorSource}\n" +
$"错误类型:{detail.ErrorType}\n" +
$"错误详情:{detail.ErrorMessage}";
Console.WriteLine(msg);
}
catch(FaultException fex)
{
Console.WriteLine(fex.Message);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
IClientChannel client = (IClientChannel)channel;
client.Close();
}

为了能够在控制台应用程序中多次调用服务(整数是随机生成,不能保证每次都抛异常),老周做了些处理,按任意键来调用服务,当然不能弄成死循环,为了使循环不死,我留了个出口——按Esc键。

如果在服务器上果真引发了FaultException<TDetail>,那么,在客户端就可以捕捉到该异常。服务器引发异常后会数据对象序列化,传到客户端后,会进行反序列化。

示例运行结果如下图所示。

【WCF】错误协定声明

好了,知识点补完了,老周得准备吃lunch了,今天是国庆长假第二天,下午老周要去朋友H家里看现场水墨绘画,据说有不少妹子在那里。

示例代码下载

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

很久没讲故事了,这回就讲一讲老周为什么会进入IT界吧。

其实原因也极其简单,也不是什么远大志向,老周之所以会进入IT领域,就是因为喜欢编程,纯粹就是爱编程,不等于爱做项目,老周很讨厌做项目。

还是孔爷爷说得好,“知之者不如好之者,好之者不如乐之者”,对老周而言,除了卖保险之外,什么行业都可以进,要不是热爱编程,老周是不会选择走IT道路。而编程里面,犹爱.NET。

所以,以后你要是想跟老周讨论编程问题,那就只讨论编程上的事,不要跟我讨论怎么找到好工作,找工作那是你的事,跟我没关系,也不要讨论.net有什么前景之类的话题,那是匹夫才讨论的问题。不过,最近些天,好像又有些不学无术的人,又在搞.NET与Java之争,那些东西在老周眼里,等同于看一场相声表演而已。

反正老周只告诉你一句话:我就是热爱.NET。

如果你喜欢.NET,欢迎你看看老周写的烂文章;如果你不喜欢.NET,那无所谓,你可以无视老周的博客。但是,老周不允许有人在博客评论里面说不文明的言论。心诚则与君交,心不诚则与君绝。

【WCF】错误协定声明的更多相关文章

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

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

  2. 【WCF】错误处理(三):错误协定

    最近折腾换电脑的事,博客就更新慢了点.好,不废话,直入正题. 前面老周介绍过,SOAP消息中的错误信息是用一个 Fault 元素来包装的,前面老周也讲了其中的 FaultCode 元素,即可以对错误信 ...

  3. WCF初探-15:WCF操作协定

    前言: 在前面的文章中,我们定义服务协定时,在它的操作方法上都会加上OperationContract特性,此特性属于OperationContractAttribute 类,将OperationCo ...

  4. WCF初探-14:WCF服务协定

    前言: 在前面的文章中,我们定义的服务协定上都会有一个ServiceContract的特性来修饰,这是因为服务契约的实现要靠ServiceContractAttribute 属性定义,然后使用一个或多 ...

  5. WCF错误处理

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

  6. WCF初探-19:WCF消息协定

    WCF消息协定概述 在生成 WCF应用程序时,开发人员通常会密切关注数据结构和序列化问题,而不必关心携带数据的消息结构. 对于这些应用程序,为参数或返回值创建数据协定的过程很简单.但是,有时完全控制 ...

  7. WCF错误:由于目标计算机积极拒绝,无法连接;127&period;0&period;0&period;1&colon;3456

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

  8. WCF初探-16:WCF数据协定之基础知识

    数据协定概念 “数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每一个做数 ...

  9. WCF初探-18:WCF数据协定之KnownType

    KnownTypeAttribute 类概述 在数据到达接收终结点时,WCF 运行库尝试将数据反序列化为公共语言运行库 (CLR) 类型的实例.通过首先检查传入消息选择为反序列化而实例化的类型,以确定 ...

随机推荐

  1. 点击按钮后到底发生了什么,Touch,LongClick或者Click&quest;

    按钮点击事件详解 最近一个项目需要给应用初始界面上的动态按钮添加在不同状态的变换效果,如点击(俗一点也可称为按压)后实现背景图的更换或者图标的缩放等效果.由于按钮点击的时间有长有短,所以采用OnTou ...

  2. hadoop安装实战(mac实操)

    集群环境配置参考(http://blog.csdn.net/zcf1002797280/article/details/49500027) 参考:http://www.cnblogs.com/liul ...

  3. javascript&comma;jQuery&comma;trim&lpar;&rpar;

    JavaScript trim() Syntax string.trim() The trim() method removes whitespace from both sides of a str ...

  4. 一个null引发的错误

    写程序时,发生一个unrecognized selector的错误,很显然,这是一个经典错误,运行时找不到可调用的方法. 系统提示的reason是 -[NSNull length] 错误 经过查找,原 ...

  5. Elasticsearch 相关名词理解

    Cluster包含多个node,Indices不应该理解成动词索引,Indices可理解成关系数据库中的databases,Indices可包含多个Index,Index对应关系数据库中的databa ...

  6. So easy Webservice 5&period;WSDL 文件说明

    WSDL – WebService Description Language – Web服务描述语言 通过XML形式说明服务在什么地方-地址. 通过XML形式说明服务提供什么样的方法 – 如何调用. ...

  7. MongoDB 删除数据库

    MongoDB 删除数据库 语法 MongoDB 删除数据库的语法格式如下: db.dropDatabase() 删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名. 实例 以下 ...

  8. android studio导入包后无法import

    android studio导入jar包的方法: 1.将jar包放到module的libs目录下 2.在所导入的jar包上右键,选择“Add as library”. 其中,第二点跟eclipse不同 ...

  9. Hive 数据的导入导出

    数据的导入: 通过文件导入,使用load命令 一.导入本地文件: load data local inpath '/home/hadoop/files/emp.txt' overwrite into ...

  10. 关于阿里云Centos服务器搭建Java网站不能访问的问题

    首先阿里云提供的手册是没问题的 手工搭建 然后我在地址栏输入服务器地址之后总是提示无法访问! 输入命令 netstat -tunlp,80端口确实是在监听(这里不是8080,因为我在tomcat的配置 ...