中断式改变 在已有的数据契约(旧版本)的基础上修改了某一方(服务和客户端)的数据契约(新版本)之后服务和客户端之间不能正常通讯(单向或双向)我们称这种改变为中断式改变否则为非中断式改变例如以下改变全部是中断式改变 修改数据契约的名称或者命名空间 更改数据契约成员的顺序 修改数据契约成员的名称 修改数据契约成员的类型 增加或删除枚举成员修改枚举成员的名称(除了使用EnumMemberAttribute来使得和旧版本一致的情况) 非中断式改变 任何对不影响传输和接收数据的类型的改变都是非中断式改变在大多数情况下增加或删除数据契约成员都是非中断式改变 增加新的数据契约成员最常见的改变就是在一方增加新的数据契约成员然后将新的契约发送给旧版本契约的服务或客户端当反序列化这个类型的时候DataContractSerializer将会简单的忽略新增加的成员如果新增的是必须成员那么这种更改就是中断式改变因为新版本到旧版本没有问题但反方向(请参照缺失成员的情况)将不能正常通讯否则这种更改就是非中断式改变 版本往返旅行这是一种针对新增加数据契约成员的特殊情况是指数据传输的路径是从新版数据契约到旧版的数据契约然后又回到新版的数据契约的情况例如ClientàService A àService B(Client和Service B都使用的新版数据契约而Service A使用的是旧版的数据契约这是常见的调用服务链的情况)ClientàServiceàClient(Client使用的是新版数据契约Service使用的是旧版的数据契约这是服务操作的输入参数和输出参数或返回值都使用相同的数据契约的情况) 按照的规则在数据从新版本到旧版本时DataContractSerializer将会忽略新增加的数据那么Service B和Client将都接收到没有新增数据契约成员的数据那有没有办法让它们接收到包含新增数据契约成员的数据呢?答案是肯定的WCF中提供了IExtensibleDataObject接口来实现这个目的在反序列化时将新增数据放在ExtensionDataObject中以保证在后续的其他传输过程中新增数据可用 public interface IExtensibleDataObject { ExtensionDataObject ExtensionData {get;set;} } 当然即使数据契约的类型实现了IExtensibleDataObject接口你也可以通过ServiceBehaviorAttribute的IgnoreExtensionDataObject属性来强制DataContractSerializer来忽略新增成员 缺失数据成员如果对旧数据契约的更改是删除数据契约成员的话存在以下情况 ◆缺失的数据成员在数据契约中不是必须的 该数据成员(DataMemberAttriubte)的IsRequired属性值没有设置或者是false针对这种缺失数据成员在反序列化时这个缺失成员将使用缺省值或者null你也可以使用OnDeserializingAttribute或者OnDeserizlizedAttribute来设置你所希望的缺省值这属于非中断式改变 ◆缺失的数据成员在数据契约中是必须的 如果缺失的数据成员在数据契约中是必须的在反序列化时将会抛出异常这种情况属于中断式改变 其他如果将DataMemberAttribute的EmitDefaultValue属性设置成false(缺省值为true)而且在序列化时该值就是缺省值那么此数据成员将不会被序列化在另外一端将会形成缺失数据成员的情况也就是说如果该成员是必须的那么在反序列化时将会抛出异常 如果将DataMemberAttribute的EmitDefaultValue属性设置成false(缺省值为true)在反序列化时将不能接受缺省值此时如果该成员是必须的话同样会抛出异常 |