在WCF中,数据契约的应用是一个十分重要而且基础的操作技术。那么今天我们将会在这篇文章中为大家详细讲解一下有关WCF数据契约变更的相关知识,以方便大家在实际应用中获得一些帮助。#t#
Person DataContract 定义了两个属性:FirstName 和LastName。如果客户端引用了这个服务,而你后来将LastName改成SurName,实际上客户端不会中断,但是在客户端的代理类上的LastName属性会显示为空的。这是因为当客户端解串信息到Person类的时候,不会找到任何叫做Lastname的元素。
这个简单的WCF数据契约变更不会引起客户端的错误,但它会导致更严重的问题:一个意外的行为。这个错误很容易跟踪,但是跟踪变更行为是非常困难的。
这个简单的例子说明为什么任何服务变更和它们后续的影响是至关重要的。除非你自己知道利用你的web服务的每个客户端应用程序,否则变更会是个灾难。作为一名开发人员,你需要尽一切努力使你的客户端避免变更的出现。
首先,你可以应用一些***的方法来帮助客户端免于内部变更。WCF数据契约变更的更新版本如以下所示:
- [DataContract(Namespace="http://types.mycompany.com/2009/05/25",
Name="PersonContract")]- public class Person : IExtensibleDataObject
- {
- private string _firstName = string.Empty;
- private string _lastName = string.Empty;
- private ExtensionDataObject _extensionData;
- [DataMember(Name="FirstName")]
- public string FirstName
- {
- get { return _firstName; }
- set { _firstName = value; }
- }
- [DataMember(Name="LastName")]
- public string LastName
- {
- get { return _lastName; }
- set { _lastName = value; }
- }
- public ExtensionDataObject ExtensionData
- {
- get { return _extensionData; }
- set { _extensionData = value; }
- }
- }
在DataContract上增加的Namespace, Name和Order参数以及DataMember属性控制DataContractSerializer的行为。当服务的reference被添加的时候,这个增加的东西生成客户端代理。Name参数让serializer使用所指出的值,而不是实际公布的成员或是属性的名字。这个方法在没有影响客户端的情况下允许变更的内部执行。例如,考虑以下的WCF数据契约变更:
- [DataMember(Name="LastName")]
- public string SurName
- {
- get { return _lastName; }
- set { _lastName = value; }
- }
将"FirstName" 改成"SurName"的属性名字变更不会中断现有的客户端,因为客户端使用的Name参数仍然是"FirstName."。只是内部执行被该改变了。
第二个显著的变化是增加了IExtensibleDataObject接口。执行这个接口允许客户端保留在契约中没有明确定义的数据。这似乎看上去没什么用,但是在客户端希望执行示例Person对象并返回它的情况下,客户端可以保留新的数据项目。例如,用以下不会强迫现有的客户端进行更新的新成员来更新PersonContract:
- [DataMember(Name = "MiddleName", Order = 3)]
- public string SurName
- {
- get { return _middleName; }
- set { _middleName = value; }
- }
实际上,这个成员通过往返过程的服务,允许现存的客户端保留放在"MiddleName"中的值。执行IExtensibleDataObject对你的WCF数据契约变更未来的论证是一个有益的方法。
请记住,实际上客户端对一个外部构架有验证信息的选择权。(对WCF应用程序添加信息构架验证的详细讨论,请阅读此文章this article)。因此,当处理数据契约的变更时你有两种情况需要考虑:有构架验证和没有构架验证。
当客户端添加构架验证的时候,在数据契约中进行添加,变更或是减去任何项目将导致验证的失败。所以,在严格的构架验证被使用的情况下,不能对契约进行改变。相反,你需要创建一个完整的新的契约并在这个契约中使用不同的命名空间来显示新版本。
例如,从执行的角度来看,你需要两个单独的服务终端使这两个版本可用:
Original Version: [DataContract(Namespace="http://schemas.mycompany.com/2009/05/25")]
New Version: [DataContract(Namespace=http://schemas.mycompany.com/2009/06/18)]
幸运的是,严格的构架验证不是默认的行为。这意思是在没有中断服务端的情况下,你可以添加或删除数据成员。但是,由于先前所讨论的有不预期的行为会产生,删除数据成员不是一个好主意。另一方面,添加一个数据成员是很容易做到的,而且consumers会忽略它们还没有意识到的外部成员。
关键的做法是使用DataMember属性(先前讨论过的)的Order参数。使用这个参数可以告诉serializers什么样的顺序(每个成员的)可以出现在XML中
来自基础类型的成员
没有order参数(按字母顺序排列)的成员
有order参数(按值排列)的成员
WCF数据契约变更考虑的***情况是改变一个数据成员的类型。这种情况下,***的方法是创建一个新版本的数据契约并带有新的服务契约,执行和终端。