Welcome

首页 / 软件开发 / WCF / WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[下篇]

WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[下篇]2012-11-17 博客园 ArtechWCF客户端和服务端的框架体系相互协作,使得开发人员可以按照我们熟悉的方式进行异常的处理:在服务操作执行过程中抛出异常(FaultException),在调用服务时捕获异常,完全感觉不到“分布式”的存在,如同典型的“本地”操作一般。为了实现这样的效果,WCF在内部为我们作了很多。

消息交换是WCF进行通信的唯一手段,消息不仅仅是正常服务调用请求和回复的载体,服务端抛出的异常,甚至是服务的元数据都是通过消息的形式传向客户端的。所以,实现异常与消息之间的转换是整个异常处理体系的核心,而WCF的异常处理框架就着力于完成这样的功能。

我们可以这样来简单地描述WCF异常处理框架的功能实现:WCF服务端将抛出的FaultException异常进行序列化,并根绝消息的SOAP规范(SOAP 1.1或SOAP 1.2)和WS-Addressing规范(WS-Addressing 2004和WS-Addressing 1.0)生成Fault消息。被传入信道层,经过一系列的信道后,该Fault消息最终借助于传输层返回到客户端;客户端信道层接收到该Fault消息并经过相应的处理后,被反序列化。反序列化的结果即实现对FaultException的重建,WCF最终将重建的FaultException异常抛出,对于最终的开发者而言,感觉就像服务端抛出的FaultException直接被客户端捕获了一样。在上面的内容中我们说过:WCF并不直接进行FaultException和Fault消息之间的转换,而是借助于MessageFault这一中间对象。右图体现了错误(Fault)在整个WCF异常处理过程中的流转。

通过中篇的介绍,我们知道:对FaultException进行序列化和反序列化的核心对象是FaultFormatter,了解WCF整个异常处理框架的实现原理首先需要知道FaultFormatter是如何创建的。

一、FaultFormatter是如何创建的?

WCF的服务端和客户端均需要一个FaultFormatter对象,分别用于对FaultException异常对象的序列化和反序列化,现在我们分别介绍FaultFormatter对象在服务端和客户端是如何被创建的。

1、FaultFormatter(DispatchFaultFormatter)在服务端如何被创建

FaultFormatter在服务端创建于服务寄宿之时。具体来讲,在ServiceHost被初始化过程中,WCF会为服务的每个终结点创建相应的终结点分发器(EndpointDispatcher)。而对于每一个被创建出来的终结点分发器都具有一个相应的分发运行时(DispatchRuntime)。DispatchRuntime是整个WCF运行时框架的核心,一系列的对象和组件被它引用以实现对整个消息分发和操作执行行为的控制。(关于整个服务寄宿在WCF服务端框架内的执行流程,在《WCF技术剖析(卷1)》的第7章有详细的介绍。)

在DispatchRuntime的初始化过程中,WCF会根据服务的描述创建一系列的DispatchOperation对象。DispatchOperation对象可以看成是某个服务操作在运行时的表示,最终对服务操作的执行就是通过它来完成的。具体来讲,WCF会获取当前终结点的契约描述(ContractDescription),遍历每一个操作描述(OperationDescription)借此创建相应的DispatchOperation。ServiceEndpoint、ContractDescription和OperationDescription三者之间的关系通过下面的类型定义代码一目了然。

 1: public class ServiceEndpoint
2: {
3: //其他成员
4: public ContractDescription Contract { get; }
5: }
6: public class ContractDescription
7: {
8: //其他成员
9: public OperationDescriptionCollection Operations { get; }
10: }
11: public class OperationDescription
12: {
13: //其他成员
14: public FaultDescriptionCollection Faults { get; }
15: }
对于作为操作描述的OperationDescription类型,有一个与本章主题相关的类型为System.ServiceModel.Description.FaultDescriptionCollection的集合属性:Faults,表示与本操作相关的所有错误描述的集合。该集合的每一个元素为System.ServiceModel.Description.FaultDescription对象,FaultDescription对象是对应用在操作上的FaultContractAttribute特性反射所得。FaultDescription的定义如下,可见它与FaultContractAttribute的结构定义完全一样。

 1: public class FaultDescription
2: {
3://其他成员
4: public string Action { get; internal set; }
5: public Type DetailType { get; set; }
6: public bool HasProtectionLevel { get; }
7: public string Name { get; set; }
8: public string Namespace { get; set; }
9: public ProtectionLevel ProtectionLevel { get; set; }
10: }
当WCF服务端运行时以操作描述为基础创建相应的DispatchOperation后,会根据错误描述创建FaultFormatter对象,声明类型为IDispatchFaultFormatter。

 1: public sealed class DispatchOperation
2: {
3: //其他成员
4: public SynchronizedCollection<FaultContractInfo> FaultContractInfos
5: { get; }
6: internal IDispatchFaultFormatter FaultFormatter { get; set; }
7: }
从上面的代码片断还会看到,除了一个内部属性FaultFormatter之外,还具有一个类型为SynchronizedCollection<FaultContractInfo>的集合属性:FaultContractInfos。而作为集合元素的System.ServiceModel.Dispatcher.FaultContractInfo对象表示错误契约相关的信息,该集合于操作描述(OperationDescription)的Faults属性相匹配。实际上,FaultContractInfo仅仅包含两项用于实现序列化的信息:错误明细类型和Action,这可以从FaultContractInfo的定义看出来:

 1: public class FaultContractInfo
2: {
3: //其他成员
4: public string Action { get; }
5: public Type Detail { get; }
6: }