在缺失成员的情况下,如果仅仅是为缺少的成员赋予默认值,有时候会出现无法预料的错误。原因在于缺失的成员有可能是正确执行操作的必要条件。为了避免出现这样的情况,可以将缺失的成员设置为必备成员,方法是利用DataMember特性的IsRequired属性,将其值设置为true。例如:
如果消息中的成员被标记为必备成员,当接收端的DataContractSerializer无法找到所需的信息进行反序列化时,就会取消这次调用,发送端会引发NetDispatcherFaultException异常。例如,服务端的数据契约如上的定义,其中Address字段为必备成员,而客户端的数据契约则如下所示:[DataContract] struct Contact { [DataMember] public string FirstName; [DataMember] public string LastName; [DataMember(IsRequired = true)] public string Address; }
此时,如果客户端向服务发出调用,则由于引发了异常,该调用就不会到达服务。[DataContract] struct Contact { [DataMember] public string FirstName; [DataMember] public string LastName; }
客户端和服务都能够将它们的数据契约中的部分或所有数据成员标记为必备,彼此之间是完全独立的。被标记为必备的成员越多,则与服务或客户端之间的交互就越安全,但这却是以牺牲灵活性与版本兼容性为代价的。
本书总结了数据契约版本控制的几种情形,并以表显示了必备成员的版本兼容性:
| IsRequired | V1 to V2 | V2 to V1 |
| False | Yes | Yes |
| True | No | Yes |
V1到V2:代表了缺失成员的情况。如果IsRequired为false,则交互正常,对于缺失成员则设置为默认值。如果IsRequired为true,就会抛出异常,消息不能正常发送。
V2到V1:代表了新增成员的情况。不管IsRequired的值为true还是false,WCF均以忽略新成员的方式进行交互,交互正常。
WCF对于一些特殊的数据类型,支持仍然不够。这在一定程度上限制了CLR开发人员对WCF的设计。这些特殊的数据类型包括:枚举、委托、DataSet和DataTable、泛型、集合。
枚举
WCF对枚举的支持还算不错。首先,枚举类型自身是支持序列化的。不需要设置任何特性,枚举类型的所有成员都会是数据契约的一部分。如果,枚举类型中只有一部分成员需要成为数据契约的一部分,就需要用到DataContract与EnumMember特性。例如:
客户端生成的表示形式则为:[DataContract] enum ContactType { [EnumMember] Customer, [EnumMember] Vendor, //Will not be part of data contract Partner }
委托enum ContactType { Customer, Vendor }
WCF对委托以及事件的支持都不够好。这是因为委托的内部调用列表的具体结构是本地的,客户端或服务无法跨服务边界共享委托列表的结构。此外,我们不能保证内部列表中的目标对象都是可序列化的,或者都是有效的数据契约。这会导致序列化的操作时而成功,时而失败。因此,非常好的实践是不要将委托成员或事件作为数据契约的一部分。