--前言
最近各种事忙的把之前的WCF学习给耽误了一些,今天抽时间把之前的学习内容给总结了一下,因为知识点比较细碎没有做太多的练习示例,只是对其中关键的知识点做了总结,希望可以对大家有所帮助。
第六章 数据协定
6.1 数据协定的概述
默认的情况下WCF使用称之为数据协定序列化程序的序列化引擎对数据进行序列化和反序列化,所有的.NET Framework基元类型,如整型、字符串型,以及某些被视为基元的类型,如DateTime、XmlElement不需要做其他工作就可以被序列化,并被视拥有默认的数据协定。
在通常情况下通过DataContractAttribute属性应用到新建的复杂类型来完成复杂类型的序列化,此外该属性也可应用到类、结构和枚举。
在为复杂类型添加DataContractAttibute属性之后必须将DataMemberAttribute属性应用到数据协定类型的每个成员,表示应对这些数据成员进行序列化。
6.1.1 需要注意的关键点
l 数据协定使用“选择性加入”编程模型设计,对于未使用DataMemberAttribute属性标记的内容不序列化。
l DataMemberAttribute属性可应用于字段、属性、事件。
l 成员可访问性级别对数据协定无任何影响。
l DataMemberAttribute属性应用于静态成员时,该属性被忽略。
l 在序列化和反序列化期间,分别调用property-get或property-set代码进行序列化和反序列化(反序列化时先创建未初始化对象,而非在该类型上调用构造函数,最后反序列化所有数据成员)
l 对应将要生效的数据协定,必须能够序列化其所有数据成员。
l 泛型类型的处理方式与非泛型的处理完全相同。
6.2 数据协定的名称
在实际过程中,客户端、服务端可能共享不同的类型,只要数据协定相等,两端仍然可以相互传递数据。
需要注意的是完全限定的数据协定名称由命名空间+协定名称组成,而数据成员只有名称没有命名空间,且在处理协定时WCF对于命名空间、数据协定、数据成员等区分大小写。
具体的名称如下:
数据协定命名空间:
采用统一资源标识符,只需设置DataContractAttributed的NameSpace属性即可
示例:
[DataContract(Namespace="WCFDataContract")]
public class Hello {}
数据协定名称:
默认的数据协定的名称为该类型名,如果期望对其重命名可以通过DataContractAttributed的Name属性来实现
示例:
[DataContract(Name="Olive")]
Public class Hello{}
数据成员名称:
默认的数据成员的名称为该数据成员的名称,可以通过DataMemberAttributed的Name属性来对其进行重命名。
示例:
[DataMember(Name="LASTNAME")]
public string LastName { get; set; }
6.3 数据协定的等效性
数据协定的等效性分为三部分:数据协定的等效性和数据成员的等效性、数据成员顺序等效性。
6.3.1 数据协定和数据成员的等效性
要使数据协定等效,其命名空间和名称必须相同,在某一端上的每个数据成员还必须在另一端上有等效的数据成员。
要使数据成员等效,其名称必须相同,同时还必须表示同一类型的数据,即数据协定也必须等效。
如果发送或接受方存在两种类型,而其数据协定又不等效,则不应为其指定相同的名称和命名空间,否则会引发异常。
示例如下:
以下这两个数据协定是等效的
[DataContract] Pulic class Customer { [DataMember] Public string fullName; [DataMember] Public string telephoneNumber; } [DataContract(Name=’Customer”)] Public class Person { [DataMember(Name=’fullName”)] Private string nameOfPerson; Private string address; [DataMember(Name=’telephoneNumber”)] Private string phoneNumber; }
6.3.2 数据成员顺序的等效性
使用DataMemberAttribute类的Order属性可以影响数据协定的等效性,其成员必须以相同顺序出现,这样数据协定才会等效,默认按字母顺序。
示例:
[DataMember(Name="LASTNAME",Order=1)]
public string LastName { get; set; }
数据排序的基本规则:
- 如果数据协定类型为继承层次之一,则基类类型数据成员始终排在第一位
- 排在下一位的为当前数据类型的数据成员,默认按字母顺序排序,
- 再下边为设置了DataMemberAttribute属性的Order属性的数据成员,按order值升序排列,如果遇到多个成员有相同order值则对这些成员按字母排列。
示例如下:
[DataContract] Public class BaseType { [DataMember] Public string zebra; } [DataContract] Public class DervicedType:BaseType { [DataMeber(Order=0)] Public string bird; [DataMember(Order=1)] Public string parrot; [DataMember] Public string dog; [DataMember(Order=3)] Public string antelope; [DataMember] Public string cat; [DataMember(Order=1)] Public string albatross; }
以上该协定产生的数据的顺序如下:
<DerivedType> <zebra/>//首先是继承基类的数据成员 <cat/>//其次派生类中没有用order标注的数据成员,按照成员名的字母排序列车,c在的之前所以先是cat,然后是dog <dog/> <bird/>然后按照order属性的有小到大排列 <albatross/>//如果order值相等则按照数据名称排序 <parrot/> <antelope/> </DerivedType>
6.4 数据协定已知的类型
数据协定的已知类型有以下几种情况:
l 发送的数据协定源自于预期的数据协定(即发送的数据协定派生自服务端的数据协定)
l 要传输的信息的声明为接口
l 要传输的信息声明类型是Object
l 有些类型具有属于上述三种类别之一的成员,(包括.NET Framework类型)
KnownTypeAttribute类
通过首先检查传入消息选择为反序列化为实例化的类型,以确定消息内容遵循的数据协定,然后反序列话引擎尝试查找实现与消息内容兼容的数据协定的CLR类型。
反序列引擎在此过程中,允许的候选类型集成为反序列程序的“已知类型”集。
通过使用KnownTypeAttribute类型可以让反序列化引擎了解某个类型。
但是需要注意以下几点:
l 不能将数据协定用于单个数据成员,只能用于整个数据协定类型
l 可以将多个KnownTypeAttribute属性应用于同一类型
l 可将属性应用于可能成为类或结构的“外部类型”,应用属性会将其指定为已知类型,
6.5 数据协定版本管理
数据协定版本管理主要用来区分数据协定的重大更改和非重大更改,对数据协定的非重大更改并不影响应用程序的通信,但是如果是重大更改则会阻止单向或双向的通信。
对数据协定的哪些更改是重大更改呢?
l 更改数据协定的Name或Namespace值
l 通过DataMemberAttribute的Order属性来更改数据成员的顺序
l 重命名数据成员
l 更改数据成员的数据协定
l 将DataMemberAttribute的IsRequired属性设置为true即为必须数据成员,添加必须的数据成员是重大更改。
l 移除在任何早起版本中标记为必须成员的数据成员也是重大更改。
l 如果类型的任何早起版本都没有相应的数据成员,将该属性值从false更改为true就可能是重大改变。
以上这些都属于重大的更改。
需要注意的是:将IsRequired属性值从true更为false不是重大更改不是重大的更改