您所在的位置: 首页>>开发>>语言&工具>>

WCF中的Data Contract(4):WCF Data Contract Versioning(2)

http://developer.51cto.com  2008-03-11 13:59  Artech  博客园  我要评论(0)
  • 摘要:在系统开发过程中,通过对Data Type添加额外的字段进而对其进行扩展,是一个种很常见的场景。本部分就作中介绍Data Contract的这种变化,Service或者Client的Data Contract在本地添加一个新的Data Member会造成怎样的影响,WCF可以采用怎样的机制来解决这种单方面Data Contract版本的改变。
  • 标签:WCF  Data Contract  Service  Client

现在我们在Client端为Custom添加一个新的成员,ShippingAddress,通过重写ToString方法:

namespace Artech.DataContractVersioning.Client
{
[DataContract(Name="Order",Namespace="http://artech.datacontractversioning")]
public class CustomOrder
{
[DataMember(Order = 0, Name="OrderID")]
public Guid OrderNo
{ get; set; }

[DataMember(Order = 2, Name = "SupplierID")]
public Guid SupplierNo
{ get; set; }

[DataMember(Order = 1)]
public DateTime OrderDate
{ get; set; }

[DataMember(Order = 3)]
public string ShippingAddress
{ get; set; }

public override string ToString()
{
return string.Format("Order No.\t: {0}\nSupplier No.\t: {1}\nOrder Date:\t:

{2}\nShipping Address: {3}", this.OrderNo, this.SupplierNo,

this.OrderDate, this.ShippingAddress);
}
}
}

我们来看看Client端程序运行的输出结果:

图1

通过上面的结果,我们发现Shipping Address的信息在经过Service处理后丢失了。原因很简单,Service端的Data Contract根本就没有ShippingAddress成员,所有在反序列化生成Order对象的时候将会忽略ShippingAddress的信息。

其实这是一个不太合理的状况,对于Client来说,我指定了对象的某个对象的某个成员的值,结果Service处理返回后,却无缘无故(对于Client来说是无缘无故)丢失了。其实这种情况还出来在另一种场景之中:Client先调用Service A,Service B再将相同的对象作为参数调用Service C,现在假设Client和Service B的Data Contract是CustomOrder,Service A的Data Contract是少一个ShippingAddress的Order,那么经过Service A反序列化的对象将会是缺少Shipping Address的Order对象,然后这个Order对象又由Service A传导Service B,虽然Service B能过识别Shipping Address成员,但是现在却没有改成员的值了,这显然是有问题的。我们把这样的问题称为Round trip问题,我们必须解决这样一个问题。

其实在WCF中解决这样一个问题的方案简单而直接,那就是在Data Contract中定义一个额外的成员来存储没有在成员列表中定义的信息。我们可以让Data Contract的Data Type实现System.Runtime.Serialization.IExtensibleDataObject Interface来解决Round trip的版本问题。Interface的定义如下,他仅仅有一个Property成员:ExtensionData。

namespace System.Runtime.Serialization
{
// Summary:
//     Provides a data structure to store extra data encountered by the System.Runtime

.Serialization.XmlObjectSerializer
//     during deserialization of a type marked with the System.Runtime.Serialization.

DataContractAttribute
//     attribute.
public interface IExtensibleDataObject
{
// Summary:
//     Gets or sets the structure that contains extra data.
//
// Returns:
//     An System.Runtime.Serialization.ExtensionDataObject that contains data that
//     is not recognized as belonging to the data contract.
ExtensionDataObject ExtensionData { get; set; }
}
}

现在我们来重新定义Service的Order Data Contract:


namespace Artech.DataContractVersioning.Service
{
[DataContract(Namespace="http://artech.datacontractversioning")]
public class Order:IExtensibleDataObject
{
[DataMember(Order = 0)]
public Guid OrderID
{get;set;}

[DataMember(Order = 1)]
public DateTime OrderDate
{ get; set; }

[DataMember(Order = 2)]
public Guid SupplierID
{ get; set; }


public ExtensionDataObject ExtensionData
{
get;
set;
}
}
}

我们再来运行一下client端程序,我们发现现在没有数据丢失了:

图2

这就是实现了IExtensibleDataObject Interface的效果。就其本质,很简单,对于实现了该Interface的Data contract,将通过一个ExtensionDataObject 类型的对象来保存和获取那些没有在Data Contract定义的成员。为了一窥Order的ExtensionData属性中保存的内容,我们在Service进行Debug,在QuickWatch中看看它是不是真的保存了不能识别的ShippingAddress:

图3

【责任编辑:碧海蓝天 TEL:(010)68476606】



共2页: 上一页 [1] 2
【内容导航】
WCF开发基础
深入Vista应用程序开发
走向银光 —— 一步一步学Silverlight2
让你的代码“炫”起来——WPF开发教程
WebSphere 实现SOA的利器
 
 验证码: (点击刷新验证码)   匿名发表
  • Visual C++ 完全自学宝典

  • 作者:强锋科技,朱洪波
  • Visual C++ 6.0是微软公司为程序人员提供的Visual Studio 6.0工具套件中的重要组成部分。本书由浅入深地介绍使用Visual C++ 6.0..
Copyright©2005-2008 51CTO.COM 版权所有