第八讲:数据契约版本控制

代码

https://yunpan.cn/cPns5DkGnRGNs   密码:3913


 

数据契约是对用于交换的数据结构的描述,是数据序列化和反序列的依据。

在一个WCF应用中,客户端和服务端必须通过等效的数据契约进行有效的数据交换。随着时间的推移,不可避免的,我们会面临着数据契约版本的变化。比如数据成员的添加和删除等。

 

数据契约版本的差异最主要的表现形式是数据成员的添加和删除。如何保证在数据契约中添加一个新的数据成员,或者是从数据契约中删除一个现有的数据成员的情况下,还能保证现有客户端的正常服务调用(对于服务提供者),或者对现有服务的正常调用(针对服务消费者),这是数据契约版本控制要解决的问题。

 

例如:这个  场景描述

 

 1     /// <summary>
 2     /// 版本V1
 3     /// </summary>
 4 
 5     [DataContract]
 6     public class CustomerV1
 7     {
 8         [DataMember]
 9         public string Name { get; set; }
10         [DataMember]
11         public string PhoneNo { get; set; }
12         [DataMember]
13         public string Address { get; set; }
14     }
15 
16     /// <summary>
17     /// 版本V2
18     /// </summary>
19     [DataContract]
20     public class CustomerV2
21     {
22         [DataMember]
23         public string Name { get; set; }
24         [DataMember]
25         public string PhoneNo { get; set; }
26 
27     }

 

数据契约成员的移除导致在发送—回传过程中数据的丢失问题。客户端基于数据契约CustomerV1进行服务调用,而服务的实现却是基于CustomerV2的,那么序列化的CustomerV1对象生成的XML通过消息传到服务端,服务端会按照CustomerV2进行反序列化,毫无疑问Address的数据会丢失。如果Customer的信息需要返回到客户端,服务需要对CustomerV2对象进行序列化,则序列化生成的XML肯定没有Address数据成员存在。当回复消息返回到客户端时,客户端按照CustomerV1进行反序列化生成CustomerV1对象,会发现原本赋了值的Address属性现在变成了null。

对于客户端来说,这是一件怪事也是不可接受的事情:“为何数据经过发送—回传后会无缘无故的丢失呢”?

 

 

为了解决这个问题

WCF定义了一个特殊的接口System.Runtime.Serialization.IExtensibleDataObject,该接口中仅仅定义了一个ExtensionDataObject类型属性成员,对于实现了IExtensibleDataObject的数据契约,WCF在进行序列化时会将ExtensionData属性的值也序列化到XML;在反序列化过程中,如果发现XML包含有数据契约中没有的数据,会将多余的数据进行反序列化,并将其放入ExtensionData属性中保存起来,由此解决数据丢失的问题。


 

 

我们可以测试一下,根据第六讲的  1.数据契约基本的使用  的  代码  进行 测试。

打开  ContentTypes 项目下的 ListItem 数据契约类,注释在该类的最后一个属性  Url  

[ 8-01 ]

 

然后我们将整个项目  重新生成一遍,然后 启动 Hosting,启动WinFrom(这里先不不要 更新服务引用 )  ,在文本框中输入  响应的  字符串

点击 保存 按钮,最后点击 获取 按钮。

这个时候你会发现 你刚才输入的   网站  的 文本框中 的 字符串消失了。

 

这是因为服务器 是按照 你刚才改动的  数据契约  进行响应的处理,而客户端 再你没有 更新服务引用的情况下 ,是用的  之前的 数据契约  进行  传递数据的 , 之前的 数据契约 有 Url 这个属性,但是  服务器 修改后  的 服务契约 中是 没有 Url 这个属性的。

那客户端 我传了  Url  的值,凭什么 返回来  就没有数据了?难道  你服务器  版本更新了,我就也要  进行版本更新?  那 万一  别的很多已经下载过  你的软件,而因为你的服务器更新,就不能用了吗?这样肯定不行。

 

这样说把,服务器版本更新了,无非就是  数据契约  新增了 属性 或者  删除了属性。  那我客户端没有更新,客户端的版本比服务器版本低。 客户端 传了 某个 服务器已经删除的 属性,服务器你不管,忽略就是了,但是 服务器回传的 时候 一定也要把 我这个被你忽略的 属性 值  给 原样返回就是了。

同理,如果服务器要是增加了 新的属性,我客户端是老版本没有这个最新的数据契约的 属性,那客户端不知道有这个属性,就不传,服务端的这个属性会是个NULL 。

 

如何做呢?

让我们的  数据契约 去继承  IExtensibleDataObject  这个接口,并且实现该接口

 

[ 8-02 ]

 

 

 

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Runtime.Serialization;
 6 
 7 namespace ContentTypes
 8 {
 9     [DataContract(Namespace = "http://www.HulkXu.com/")]
10     //[DataContract]
11     public class ListItem : IExtensibleDataObject
12     {
13         [DataMember(Name = "Id", IsRequired = false, Order = 0)]
14         //[DataMember]
15         private long m_id;
16 
17         public long Id
18         {
19             get { return m_id; }
20             set { m_id = value; }
21         }
22         //[DataMember]
23         [DataMember(Name = "Title", IsRequired = true, Order = 1)]
24         private string m_title;
25 
26         public string Title
27         {
28             get { return m_title; }
29             set { m_title = value; }
30         }
31         //[DataMember]
32         [DataMember(Name = "Description", IsRequired = true, Order = 2)]
33         private string m_description;
34 
35         public string Description
36         {
37             get { return m_description; }
38             set { m_description = value; }
39         }
40         //[DataMember]
41         [DataMember(Name = "DateStart", IsRequired = true, Order = 3)]
42         private DateTime m_dateStart;
43 
44         public DateTime DateStart
45         {
46             get { return m_dateStart; }
47             set { m_dateStart = value; }
48         }
49         //[DataMember]
50         [DataMember(Name = "DateEnd", IsRequired = false, Order = 4)]
51         private DateTime m_dateEnd;
52 
53         public DateTime DateEnd
54         {
55             get { return m_dateEnd; }
56             set { m_dateEnd = value; }
57         }
58 
59 
60         //删除
61         //[DataMember]
62         //[DataMember(Name = "Url", IsRequired = false, Order = 5)]
63         //private string m_url;
64 
65         //public string Url
66         //{
67         //    get { return m_url; }
68         //    set { m_url = value; }
69         //}
70 
71 
72         //添加
73         //[DataMember(IsRequired=true)]
74         //private string address;
75         //public string Address
76         //{
77         //    get { return address; }
78         //    set { address = value; }
79         //}
80         //public ExtensionDataObject ExtensionData
81         //{
82         //    get;
83         //    set;
84         //}
85 
86 
87         public ExtensionDataObject ExtensionData
88         {
89             get;
90             set;
91         }
92 
93 
94     }
95 }

 

 

好的 ,关于  数据契约版本控制  就是这些了,比较简单。

 

posted @ 2016-05-15 15:54  徐朗  阅读(607)  评论(0编辑  收藏  举报