利用WSCF进行契约先行的Web Services开发
什么是契约先行(Contract-First)?
如果说一个新的软件开发模型会影响甚至改变软件开发过程,那么这样的改变对于开发人员而言,无疑是最具有深远意义的。多年以来,大多分布式应用程序的开发人员都习惯关注对象和从头开始编写一大堆的代码。然而,在面向服务(Service-Oriented)的时间,一切都将改变。从面向过程到面向对象,再到基于组件的开发(Component Based Development),软件开发领域经历着一次又一次的变革,而Web Services的盛行则将软件方法学的革新再一次的推到了浪尖口,一切都处在变化的焦点之中。
关于SOA(面向服务的体系架构)不论在工业界还是学术界,都有了太多的讨论,有称之为“后OO时代的软件体系架构”,也有人认为SOA代表未来的主流方向,但是目前并不适合大规模的进入工业应用,也有太多的专家和学者在SOA和Web Services的关系上前扯不清。纷争也罢,潮流也罢,有一点我们不得不承认,随着Web Services渐渐成为分布式应用特别是异构系统整合的标准协议,这种“服务自治,共享协定但不共享实现”的软件构造方式得到了越来越多开发人员的追捧,契约先行也正是源于此。
开发人员在定义Web Services服务契约的时候有两种选择,一种方式就是在代码实现之前首先完成WSDL的定义,我们在这里就称这种开发方式为“契约先行(Contract-First)”,另外一种方式就是首先完成代码编写,然后依赖于底层基础架构(如ASP.NET)产生契约,这种方式我们称为“代码先行”。这两种方式各有优缺点,但是大多的开发都是采用“代码先行”,例如首先利用Visual Studio.NET编写Web Services的实现,然后通过ASP.NET提供的Web Services机制生成相关的WSDL,相信大多开发人员是如此完成工作的。
“契约先行”强制要求你使用能够理解WSDL的共享语言工作,然后直接使用WSDL对于开发人员而言是一件很棘手也很不爽的事情,因为目前没有特别好的工具提供对WSDL开发的支持,传统的面向对象技术也无法做到直接完成从对象到WSDL的映射工作。利用“代码先行”则能够从某种程度上来帮助“契约先行”开发中存在的问题,正如上文提到的利用ASP.NET的ASMX(相信大家知道这是什么类型的文件)运行时产生WSDL,另外有一种做法就是利用Xml系列化产生相关的属性。但是基于模式(Schema)的开发方法在目前中是最优的,因为你可以直接定义服务消息和数据,这样做的结果是可以帮助您的服务具有更好的交互性和独立于本地代码类。但是Schema-Based的契约先行开发方式最大的挑战也再此:如何找到好的工具来帮助开发人员和架构师在设计阶段完成简化模式设计。
WSCF
而thinktecture提供的WSCF(Web Services Contract-First)正是一个这样简化开发人员契约设计工作的工具,这个工具提供了很多功能和特性来帮助开发人员将精力集中在契约先行开发中最重要的步骤:消息和操作设计。WSCF作为一个插件和Visual Studio 2003进行了非常好的集成,因此开发人员和架构师能够在不离开习惯的IDE时继续工作。
如何使用WSCF
在基于模式的契约先行开发中,不同于传统的编程语言开发,其大致可以分解成五个步骤:
1. 数据建模
在这个步骤中定义数据结构,以保证通过Web Services接口中传递的消息能够被正确交换。
2. 消息建模
确定需要进行交换的消息,这样的XML Schema可以通过XMLSpy或者VS.NET自带的XSD进行编辑。
3. 操作和接口建模
定义希望提供给Web Services消费者提供的方法操作
4. 生成代码骨架
根据上述定义的数据、消息和操作及其接口产生平台依赖的代码(如C#或者Java)。
5. 迭代契约式设计和代码生成
重复上述步骤
应用程序场景
如下我们就通过一个简单的例子展示如何使用WSCF进行契约先行开发
工程组织
首先我们创建一个空的应用解决方案,同时添加三个工程到新建的解决方案中,如下表格显示了各个工程的用途
工程名 |
工程类型 |
介绍 |
ContractMetadata |
C#空白项目 |
包含数据、消息和接口的原数据定义 |
RestaurantService |
C#空白Web项目 |
餐馆服务Web Services实现 |
RestaurantClient |
C#控制台项目 |
餐馆服务Web Services客户端实现 |
消息和数据建模
添加完毕上述的工程之后,就需要我们开始定义契约,正如上述所述,我们首要的工作是创建一个用来描述Restautant数据的XML架构,同时命名为RestautantData.xsd,具体如下图所示
图1:数据格式
与此同时,我们需要定义交换数据的消息
(图2)为此我们增加了名为RestaurantMessages.xsd的XML架构文件,为了能够引用RestaurantData.XSD的数据,我们需要手工在XSD文件中加入图3所示的代码
图2:消息定义
图3:Import语法
接口契约建模
在文章的开头提到过,接口协定表现为WSDL文档,显而易见的,没有哪个家伙愿意首先编写WSDL,如果让你去读懂WSDL规范,然后一点点的编写,那将是一个无比痛苦的过程,到目前为止,市面上也没有特别好的工具可以直接支持WSDL文档的编辑,我们需要一个从更高抽象角度的工具来界定我们的接口协定。
WSCF提供了一个WSDL生成向导,就如同ASMX运行时那样,尽其可能的对开发人员和架构是隐藏WSDL规范的技术细节,下表显示了目前WSCF对操作引用的字符串模式支持,简单的说,WSCF能够根据XSD提供的消息定义自动推断一些操作。
输入消息 |
输出消息 |
推断操作 |
XYZ |
XYZResponse |
XYZ |
XYZRequest |
XYZResponse |
XYZ |
ZYZRequestMessage |
XYZResponseMessage |
XYZ |
最后WSCF支持一些简单的WSDL迭代操作,也就意味着您可以利用生成——察看——修改——生成WSDL文档,让我们来看看如何利用WSCF的向导生成WSDL文档。
图4:利用WSCF生成WSDL文档
通过点击在RestaurantMessage.xsd的右键菜单我们可以看到如图4的界面,启动向导之后按照向导的要求一步一步完成操作,这个时候就产生了我们需要的WSDL文档,这个也是契约先行开发的最关键步骤,如图5所示,我们得到了命名为“RestaurantService.wsdl”的文档,那么剩下的工作就是开始产生代码了。
图五:ContractMedadata的文件布局
从契约产生代码
在这里我们仅讨论生成.NET平台下面的代码,对于其他平台如Java,都提供了从WSDL到Java代码的转换工作,有兴趣的读者可以参阅Eclipse或者其他Java DE的相关文档。如图6所示,WSCF支持生成客户端和服务器
的代码
我们可以根据需要生成相关的程序代码,然后实际业务情况实现具体业务细节。生成的部分代码如下所示
public class RestaurantInfo { private string name; public string Name { get { return this.name; } set { this.name = value; } } } |
其他
同时WSCF提供了一个命令行工具”wscf.exe”,它是一个基于命令行的代码生成引擎,可以通过wscf.exe –help察看详细参数使用信息。
小结
通过如上的演示我们可以看到如何利用XSD和WSCF结合实现契约先行开发,当然,不要指望通过一个工具就能够替你完成所有的工作,WSCF只是在WSDL的生成和代码生成上提供了简化的使用方式,至于如何在”代码先行”和“契约先行”之中作出选择,就依赖于你的具体应用了,一般来说,在如下场景中优先考虑“契约先行”的开发方式
1) 客户端和服务器段都还没有实现代码,并且契约变动的情况是存在的
2) 客户端和服务器段异构的,简单的说客户端和服务器段可能采用不同的平台实现,如客户端使用Java,服务器端使用.NET
3) 系统互操作的场景比较复杂