Programming WCF Services:数据契约版本控制

随着版本的不断演化,客户端与服务端的数据契约可能会出现版本不一致的情况。在WCF中,关于数据契约的版本控制有两种情况:新增成员与缺失成员。新增成员是指发送方包含了新增成员,默认处理方式为忽略新增成员。缺失成员则是指发送方缺少成员,默认处理方式是为缺失成员赋予其默认值。

在缺失成员的情况下,如果仅仅是为缺少的成员赋予默认值,有时候会出现无法预料的错误。原因在于缺失的成员有可能是正确执行操作的必要条件。为了避免出现这样的情况,可以将缺失的成员设置为必备成员,方法是利用DataMember特性的IsRequired属性,将其值设置为true。例如:

[DataContract]   
struct Contact 
{
[DataMember]
public string FirstName; [DataMember]
public
string LastName;
[DataMember(IsRequired =
true)] public string Address;
}

如果消息中的成员被标记为必备成员,当接收端的DataContractSerializer无法找到所需的信息进行反序列化时,就会取消这次调用,发送端会引发NetDispatcherFaultException异常。例如,服务端的数据契约如上的定义,其中Address字段为必备成员,而客户端的数据契约则如下所示:

[DataContract]   
struct Contact
{
[DataMember]
public string FirstName; [DataMember]
public string LastName;
}

此时,如果客户端向服务发出调用,则由于引发了异常,该调用就不会到达服务。

客户端和服务都能够将它们的数据契约中的部分或所有数据成员标记为必备,彼此之间是完全独立的。被标记为必备的成员越多,则与服务或客户端之间的交互就越安全,但这却是以牺牲灵活性与版本兼容性为代价的。

本书总结了数据契约版本控制的几种情形,并以表显示了必备成员的版本兼容性:

IsRequired V1 to V2 V2 to V1
False Yes Yes
True No Yes

假定V2包含了V1的所有数据成员,同时还定义了新增成员。则表涵盖了版本的几种情况。

V1到V2:代表了缺失成员的情况。如果IsRequired为false,则交互正常,对于缺失成员则设置为默认值。如果IsRequired为true,就会抛出异常,消息不能正常发送。

V2到V1:代表了新增成员的情况。不管IsRequired的值为true还是false,WCF均以忽略新成员的方式进行交互,交互正常。

WCF对于一些特殊的数据类型,支持仍然不够。这在一定程度上限制了CLR开发人员对WCF的设计。这些特殊的数据类型包括:枚举、委托、DataSet和DataTable、泛型、集合。

枚举

WCF对枚举的支持还算不错。首先,枚举类型自身是支持序列化的。不需要设置任何特性,枚举类型的所有成员都会是数据契约的一部分。如果,枚举类型中只有一部分成员需要成为数据契约的一部分,就需要用到DataContract与EnumMember特性。例如:

[DataContract] 
enum ContactType
{
[EnumMember] Customer,
[EnumMember]
Vendor,
//Will not be part of data contract Partner
}

客户端生成的表示形式则为: 

 enum ContactType
{
Customer,
Vendor
}

委托

WCF对委托以及事件的支持都不够好。这是因为委托的内部调用列表的具体结构是本地的,客户端或服务无法跨服务边界共享委托列表的结构。此外,我们不能保证内部列表中的目标对象都是可序列化的,或者都是有效的数据契约。这会导致序列化的操作时而成功,时而失败。因此,最佳实践是不要将委托成员或事件作为数据契约的一部分。

数据集与数据表

DataSet和DataTable类型是可序列化的,因而我们可以在服务契约中接收或返回数据表或数据集。

如果服务契约使用了DataSet和DataTable类型,生成的代理文件不会直接使用DataSet和DataTable类型,而是包含DataTable数据契约的定义(只包含DataTable的样式,而不包含任何代码)。但我们可以手工修改这些定义。例如这样的服务契约: 

[ServiceContract()]   
public interface IContactManager
{
[OperationContract]
void AddContact(Contact contact);
[OperationContract]
void AddContacts(DataTable contacts); [OperationContract]
DataTable GetContacts();
}

那么生成的代理文件可能会是这样: 

public interface IContactManager 
{
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IContactManager/AddContact", ReplyAction="http://tempuri.org/IContactManager/AddContactResponse")] [System.ServiceModel.XmlSerializerFormatAttribute()]
void AddContact(Contact contact); [System.ServiceModel.OperationContractAttribute(Action=
"http://tempuri.org/IContactManager/AddContacts", ReplyAction="http://tempuri.org/IContactManager/AddContactsResponse")] [System.ServiceModel.XmlSerializerFormatAttribute()] AddContactsResponse AddContacts(AddContactsRequest request); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IContactManager/GetContacts", ReplyAction="http://tempuri.org/IContactManager/GetContactsResponse")] [System.ServiceModel.XmlSerializerFormatAttribute()] GetContactsResponse GetContacts(GetContactsRequest request);
}
代理类的定义则如下所示:
[System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]

public
partial class ContactManagerClient : System.ServiceModel.ClientBase, IContactManager
{

//其余成员略;
public
void AddContact(Contact contact)
{
base.Channel.AddContact(contact); }
AddContactsResponse IContactManager.AddContacts(AddContactsRequest request) {

return
base.Channel.AddContacts(request);
}

public
void AddContacts(AddContactsContacts contacts)
{
AddContactsRequest inValue =
new AddContactsRequest(); inValue.contacts = contacts;
AddContactsResponse retVal = ((IContactManager)(
this)).AddContacts(inValue);
}
GetContactsResponse IContactManager.GetContacts(GetContactsRequest request) {

return
base.Channel.GetContacts(request);
}

public
GetContactsResponseGetContactsResult GetContacts()
{
GetContactsRequest inValue =
new GetContactsRequest();
GetContactsResponse retVal = ((IContactManager)(
this)).GetContacts(inValue); return retVal.GetContactsResult;
}
}

我们可以手动将AddContacts()与GetContacts()方法修改为: 

 public  void AddContacts(DataTable contacts) 
{
AddContactsRequest inValue =
new AddContactsRequest();
inValue.contacts = contacts;
AddContactsResponse retVal = ((IContactManager)(
this)).AddContacts(inValue); }
public
DataTable GetContacts()
{
GetContactsRequest inValue =
new GetContactsRequest();
GetContactsResponse retVal = ((IContactManager)(
this)).GetContacts(inValue); return retVal.GetContactsResult;
}

当然,前提条件是我们需要修改AddContactRequest类以及GetContactsResponse,例如将AddContactRequest类的contacts成员由原来的AddContactsContacts类型修改为DataTable类型;将GetContactsResponse中的GetContactsResult成员由原来的GetContactsResponseGetContactsResult类型修改为DataTable类型。

自动生成的代理类非常复杂,实际上我们完全可以简化。首先将客户端的服务契约定义修改为与服务端服务契约完全一致的定义: 

 [ServiceContract()]   
public interface IContactManager 
{
[OperationContract]
void AddContact(Contact contact);
[OperationContract]
void AddContacts(DataTable contacts); [OperationContract] DataTable GetContacts();
}

然后修改代理类ContactManagerClient:

修改后运行的结果完全相同。

注意,DataRow类型是不能序列化的。

在WCF中,还可以使用DataTable和DataSet的类型安全的子类。书中也给出了相应的例子。然而,WCF的最佳实践则是避免使用DataTable和DataSet,以及使用DataTable和DataSet的类型安全的子类。书中阐释了原因:
“对于WCF的客户端与服务而言,虽然可以通过ADO.NET和Visual Studio工具使用DataSet、DataTable以及它们的类型安全的派生对象,但这种方式过于繁琐。而且,这些数据访问类型都是特定的.NET类型。在序列化时,它们生成的数据契约样式过于复杂,很难与其它平台进行交互。在服务契约中使用数据表或者数据集还存在一个缺陷,那就是它可能暴露内部的数据结构。同时,将来对数据库样式的修改会影响到客户端。虽然在应用程序内部可以传递数据表,但如果是跨越应用程序或公有的服务边界发送数据表,却并非一个好的主意。通常情况下,更好的做法是暴露数据的操作而非数据本身。”

最好的做法是将DataTable转换为数组类型。书中提供了DataTableHelper类,可以帮助将DataTable转换为数组类型。

泛型

非常遗憾,我们并不能在数据契约中定义泛型。但是,WCF使用了一个折中的办法,使得我们可以在服务端照常使用泛型,但在生成的数据契约定义时,泛型会被具体的类型所取代,重命名的格式为:
Of

WCF还支持将自定义类型作为泛型参数。此外,还可以通过数据契约的Name属性为导出的数据契约指定不同的名字。例如,如下的服务端数据契约:

如下的服务端数据契约:

 [DataContract]   
class SomeClass
{...}
[DataContract(Name = "MyClass")]

class
MyClass
{...}
[OperationContract]
void MyMethod(MyClass obj);

导出的数据契约为:

[DataContract]   
class SomeClass 
{...}
[DataContract]
class MyClass
{...}
[OperationContract]
void MyMethod(MyClass obj);

集合

WCF支持泛型集合、定制集合,但与传统的.NET编程不一样,WCF对集合的操作存在许多约束。对于这些约束,本书描述得非常清楚。本文不再赘述。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14780914/viewspace-374777/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/14780914/viewspace-374777/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2015.11.30即将出版新书 Programming WCF Services: Design and Build Maintainable Service-Oriented Systems 4th Paperback: 1018 pages Publisher: Media; 4 edition (November 30, 2015) Language: English ISBN-10: 1491944838 ISBN-13: 978-1491944837 Programming WCF Services is the authoritative, bestselling guide to Microsoft’s unified platform for developing modern, service-oriented applications on Windows. Hailed as the definitive treatment of WCF, this guide provides unique insight, rather than documentation, to help you learn the topics and skills you need for building maintainable, extensible, and reusable WCF-based applications. Authors Juval Löwy—one of the world’s top .NET experts—and Michael Montgomery have revised this edition to include the productivity-enhancing features of .NET Framework 4.6, along with the latest WCF ideas and techniques. By teaching you the why and the how of WCF programming, this book will help you master WCF and make you a better software engineer. Learn WCF’s architecture and essential building blocks, including key concepts such as reliability and transport sessions Use built-in features such as service contracts, instance and concurrency management, transactions, queued services, and security Increase the quality of your WCF services by using design options, tips, and best practices in Löwy’s ServiceModelEx framework Understand the rationale behind particular design decisions, and rarely understood aspects of WCF development Learn why Azure Service Fabric is the killer app for modern DevOps
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值