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