契约版本处理

时间:2022-12-20 12:50:06
  • WSDL:=契约+策略.
    • 契约主要关注操作的消息类型.
    • 策略为操作描述协议.
    • 当契约变化时,使用老契约的客户应能够继续使用,并且使用新的契约内容.一旦发布.契约就确定了.
    • 但是,策略是可以改变的.如果客户端可以动态的处理变化,那么改变策略就是安全的.
  • 服务契约
    • 允许多余,缺失的参数数量.分别会被忽略,赋予默认值.
    • 对应参数和返回值的类型,若不兼容会Error.
    • 调用被删除的操作会异常.
    • 新追加的操作不能够被调用到.
  • 数据契约
    • 非必须成员,没有问题.
    • 对于必须成员(IsRequried=true),由于WCF要求其在被序列化之前必须被赋值,所以会出现异常(NetDispatcherFaultException).
    • 客户端与服务器段可以独立的设置自己的必须数据成员,越多交互越安全,但是会降低灵活性与版本兼容性.
    • 修改成员的类型.修改后类型兼容时,没有问题.不兼容时结果不定.
    • WCF对于枚举、委托、DataSet和DataTable、泛型、集合的支持有限.
      • 枚举:自身支持序列化,所以默认就是在数据契约里,当只需要其一部分被序列化时,使用EnumMember表示出需要的数据.在客户端只有被EnumMember的数据才出现在枚举定义里.
      • 委托:WCF对委托以及事件的支持都不够好。这是因为委托的内部调用列表的具体结构是本地的,客户端或服务无法跨服务边界共享委托列表的结构。此外,我们不能保证内部列表中的目标对象都是可序列化的,或者都是有效的数据契约。这会导致序列化的操作时而成功,时而失败。因此,最佳实践是不要将委托成员或事件作为数据契约的一部分.
      • 数据集和数据表: 是可以序列化的.在服务契约中使用该类型,代理类中只会有一个定义,而没有任何代码.我们可以手工修改. 然而,WCF的最佳实践则是避免使用DataTableDataSet,以及使用DataTableDataSet的类型安全的子类。这种方式过于繁琐。而且,这些数据访问类型都是特定的.NET类型。在序列化时,它们生成的数据契约样式过于复杂,很难与其它平台进行交互。在服务契约中使用数据表或者数据集还存在一个缺陷,那就是它可能暴露内部的数据结构。同时,将来对数据库样式的修改会影响到客户端。虽然在应用程序内部可以传递数据表,但如果是跨越应用程序或公有的服务边界发送数据表,却并非一个好的主意。通常情况下,更好的做法是暴露数据的操作而非数据本身最好的做法是将DataTable转换为数组类型.
      • 泛型: 不能在数据契约里定义泛型,但是,可以在服务段使用泛型,但是在生成的数据契约定义中,泛型被具体的类型(<原有名>Of<类型参数名><哈希值>)代替.WCF还支持将自定义类型作为泛型参数。此外,还可以通过数据契约的Name属性为导出的数据契约指定不同的名字.
      • 集合:WCF支持泛型集合、定制集合.但是有很多限制.对于自定义的集合应该采用
        • [KnownType(typeof(Document))]
        • [CollectionDataContract]
        •  [Serializable]
        •  public class DocumentList:IList<Document>
        • 这样,客户端应用程序可以直接使用数据契约,仍然能够识别.
  • IextensibleDataObject
    • 实现对多余数据的临时存储.
    • 客户端代理缺省对其进行了实现.这样,老版本能够保存新版本传递的数据,以便在更新时能够包含原始的数据.
    • 可以在Server端实现.来保存客户端传入的未知数据.
      • 场景:调用新版本服务,但是需要老版本进行实际的处理时.
      • 但是会带来DOS攻击和非必要的使用服务器资源的问题.
      • 可以使用配置和代码来关闭.
    • 其好处是不会导致数据丢失,但是增加了传输的数据量.
  • 版本控制
    • 只有签名变化时,才会形成新版本.
    • 1)非严格:当方法的签名变化(除添加,删除参数外,但是当该参数为重要信息时有风险)时,即删除操作或参数类型变化时才使用新版。实现:在现有的契约上添加新方法,使用相同的NameSpace,更新客户端.
    • 2)半严格:在添加操作后,要生成一个继承自旧版的一个新契约.原有的版本不再向外提供服务端点,但对原版本客户端无影响;新对新,老对老。
    • 3)新老服务之间没有任何关系。