zoukankan      html  css  js  c++  java
  • 第八讲:数据契约版本控制

    代码

    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 }

     

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

  • 相关阅读:
    JAVA(五)反射机制/Annotation
    JAVA(四)类集/枚举
    JAVA(三)JAVA常用类库/JAVA IO
    JAVA(二)异常/包及访问权限/多线程/泛型
    JAVA(一)JAVA基础/面向对象基础/高级面向对象
    【Android】Android输入子系统
    【Linux】深入理解Linux中内存管理
    【XMPP】基于XMPP的即时通讯解决方案
    cf593d
    cf593c
  • 原文地址:https://www.cnblogs.com/xulang/p/5495310.html
Copyright © 2011-2022 走看看