第二章 定义类的层次结构

定义类的层次结构

复杂类型一般在代码中以类的形式实现。复杂类更进一步通过增加特殊结构的继承关系来定义。这种方式,一个通用类型比如”price” 可以派生出为一个更加特殊的类型如”stock price” 或者 “house price”.WCF支持通过在WSDL中合适的表示的类的继承关系,在类结构和XML之间序列化和反序列化它们同时从每个类中取出属性并加入到一个集合中。

  在列表2.17中,类Price由三个元素和一个子类组成。StockPrice,继承自Price.命名空间应用到两个类上所以它们在XML中由完全合法的名字。每个元素保留自己的命名空间。

列表2.17 使用数据契约定义类的层次结构


  生成这两段XML元数据是用来支持列表2.18中显示的基础关系。首先显示Price XML元数据,其次显示StockPrice XML元数据。注意StockPrice导入Price元数据。注意在XSD中,所有的元素都是用minOccurs=0来定义,因为在代码中它们都没有使用[isRequired=true]来定义属性。

列表2.18 XML元数据中定义的类的层次结构

  一个序列化的StockPrice类型的SOAP消息体在列表2.19中显示。注意PriceStockPrice的命名空间完全通过SOAP消息体被从列表2.17的代码搬到列表2.18中的XML元数据中。

列表2.19 SOAP消息体中序列化的类层次结构

WSDL中使用KnownTypes暴露额外类型

如果数据类型满足任何先前描述的条件,那么它们会在WSDL中暴露出来。有一些额外的可能,当然,你也可能想强制一个类型包含在WSDL契约中

  举一个类继承的例子。如果一个序列化的派生类到达一个期待得到一个序列化的基类的终结点时,WCF不会知道如何反序列化这个派生类因为它不是契约的一部分。另外一个例子是一个hashtable 类,存储了其他的类作为自己的元素。WSDl将会定义hashtable类,但是不是那么存储在hashtable内部的类。

  在这些情况下,你必须告诉WCF这些应该显示包含在WSDL契约中的类。这是使用KnownTypes完成的。它可以在四种方式下完成:通过添加一个KnownType属性到[DataContract],通过在[ServiceContract]或者[OperationContract]的属性,通过在配置文件中添加一个引用给它以及它的程序集,或者通过在生成WSDL时定义它。
 
列表2.20显示了定义基类的数据契约,Price,有两个类派生自基类,StockPriceMetalPrice.注意在数据契约上的[KnownType]属性。这告诉WCF当暴露契约时要包含StockPriceMetalPriceXSD表示。这个列表也包含了服务实现。GetPrice操作是多态的,它的返回值类型可以是StockPrice或者MetalPrice,取决于哪一个操作被请求。通过代理调用GetPrice的客户端代码必须把结构强制转换成需要的类型来访问返回值类。

列表2.20 数据契约中定义的KnownType

  相应的,你可以使用[ServiceKnownType]属性在OperationContract层次定义KnownType.KnownTypes被定义在操作层时,派生类只可以在定义了已知类型的操作中使用。换句话说,并不是一个服务中的所有操作都可以使用派生类。列表2.21显示了使用[ServiceKnownType]的代码片段。在这个例子中,当消息从服务端返回时一个客户端可以调用GetPrice方法,反序列化器将创建一个StockPrice或者MetalPrice对象。但是当客户端调用SetPrice时只可以传递一个Price对象,而不是一个StockPrice或者MetalPrice对象,因为序列化器不知道在XML中如何表达这些派生类型。

列表2.21 操作契约中定义的KnownType

  无论是在数据契约层还是服务契约层,在代码中定义已知类型的劣势在于你需要在编译时就知道转化的派生类。如果一个新类型被添加,你需要重新编译代码。这可以使用两种方法来解决。

  首先,你可以把已经类型引用从代码中挪到配置文件中去,在服务配置文件中的system.runtime.serialization部分加入已经类型信息。考虑到类继承关系,你需要添加引用到基类并添加KnownType引用到派生类。这在列表2.22中显示,当EssentialWCF.Price是基类而且EssentialWCF.StockPriceEssentialWCF.MetalPrice是派生类时,StockService是寄宿这些类型的DLL.

列表2.23 配置文件中定义的KnownType


  在契约中确定派生类性的最普通方法就是在运行时生成它。这可以通过WCF暴露的钩子来完成。[KnownType][ServiceKnownType]的两个构造函数都接受字符串参数。这个字符串是在序列化或者反序列化时返回一系列已知类型的方法名。如果你使用一个原数据容器,你可以在容器或者数据库中寻找类型信息并在运行时暴露它们。列表2.23显示了一个简单的实现,显示了类型名被硬编码到GetKnownTypes方法中而不是从外部容器被拖入。

列表2.23 运行时代码中定义的KnownType

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值