Microsoft .NET和 IBM WebSphere之间契约优先Web Services的协同能力
发布日期: 2005-10-17 | 更新日期: 2005-10-17
Eric Cherng
Vertigo 软件公司
James Duff
Vertigo软件公司
Dino Chiesa
微软公司
适合的读者:
架构师和开发者
在此下载本文有关协同能力的示例
本页内容
介绍
当Web service的采用逐渐增加时,提供商努力将更多的特性和标准添加到他们的产品框架中,以使得系统之间的通讯更加便捷灵活。当各种组织花费大量的时间和金钱研究如何才能最好的支持Web services和其应用技术时,他们应该清楚:技术的实力及工艺的限制——具体来说,这些问题取决于开发者的敏捷,系统的可维护性,和协同能力。本文重点放在协同能力上,并以此为起点,研究Microsoft .NET Framework和IBM WebSphere通过Web services的协同能力。这个白皮书的目标及附带的例子展示了一个平台是如果与另一个平台协同工作的。具体的平台就是Microsoft .NET Framework和IBM WebSphere。示例可以证明:跨越基于Web services交叉平台协同能力的所有项目中,可复用的基本技术和原理是必要的。
协同能力示例内容
示例包含:
1. | Web service范例代码 • | Web services and Web service客户端中用Java and C#写的三种不同的服务接口. 1. | Web Service 1:示范了一个简单的加法Web service的例子,目的在于让读者熟悉相关工具和平台。 | 2. | Web Service 2:示范了两个平台之间短暂的复杂对象类型 | 3. | Web Service 3: 示范了一个设计模式,此模式用于创建处理数据映射变化事例的可扩展的Web services。 |
| • | 每项Web service都示范了异类平台的协同工组能力。通过改变Web service客户端的一项设置,Web service客户端可以和.NET Web service或WebSphere Web service其中之一进行通讯。 | • | 在这个简单的例子中,运行Web service和其客户端时不需要数据的存取。 | • | 本文中,我们将详细介绍如何从第一个原理中构建Web Service 1,Web Services 2 and 3的细节我们将不再累述。 |
|
2. | 在白皮书中详细讨论了每个Web services的细节和设计。 |
相关技术和概念在本文中讲述的比较概括,但可应用于两个提供商之间的平台联接。不过,本例仅基于Microsoft .NET Framework和 the IBM WebSphere SDK开发和测试了Web Services。
首先要安装的软件
本文(和相关示例)假设读者已经对.NET Framework, ASP.NET 和IBM WebSphere 应用服务器的基础知识相当熟悉。Web Service 1适用于以前从未构建过Web services或对上述两个平台没有使用经验的开发者。即使您对涉及到的Web services和两个平台相当熟悉,我们也建议你至少阅读一次Web Service 1文档,因为此文档中包含了Web Services 2 and 3中没有的信息和提示。
软件需求
创建和测试例子需要安装下列软件:
如果您没有安装任何Java软件,你必须按照如下顺序安装这些软件:
1. | Sun Java SDK v1.4 |
2. | Eclipse v2.1.3 |
3. | WSDK v5.1 |
4. | JWSDP v1.3 |
5. | 安装Eclipse前需要安装一个Java SDK,同样安装WSDK前也需要安装Java SDK,而安装WSDK前需要安装Eclipse |
6. | 更详细的安装信息在协同工作能力示例下载的README文件中可以找到。 |
为什么需要Web Services?
作为一种应用技术,Web services已经有几年的历史了。很多年前,一些机构和公司为Web services创建了标准。商业分析师、架构师、软件工程师认识到公司的数据需要被多种系统传播,这些系统彼此之间需要通讯。以前企图通过基于RMI、DCOM和其他特殊平台内部连接机制的技术将应用程序连接起来,但是这种尝试失败了,因为跨越不同组织的提供商和平台各异。还有一个原因就是这种方法不适用于应答信息很慢甚至不存在的互联网。可替代的办法是使用消息队列,PUT/GET动词,和手动消息集合,但是这种方法存在可维护性和程序员效率的问题。因此,开发者开始借助于运用一些相同的标准和协议,例如:XML 和 HTTP。
开发者选择了XML和HTTP构建彼此能够通讯的应用程序,因为XML可以被几乎所有平台应用和支持,而HTTP运用也非常广泛并有穿越防火墙的能力。诸如Microsoft 和 IBM这样的提供商开始构建框架用以支持上述成就并致力于减轻开发者的工作。构造框架通过消除XML序列化和反序列化的负担,并通过提供诸如构建系统连接代码这样的基础模块来完成。随着Web services的诞生,异构系统和应用程序间的整合将会变得更加容易。运用Web services作为催化剂,提供商正在整合面向服务架构的观念,其中个人解决方案可以被彼此连接使得实时数据可以在企业间流动,这些解决方案仍然会使用到私有的RPC协议,例如RMI 和 DCOM。
因此综合来说,其存在是有益并有潜力的。但是,实际上,很多开发者发现创建共用的Web services是一个挑战。哪怕创建一个最简单的Web services都存在许多潜在的危险,例如类型冲突,不支持属性。我们的第一个示例将向你展示一个公用Web service的例子,并带领你漫步在设计和创建这样的一个Web service的过程中。
Web Service 1:加法
第一个示例示范了Web service协同能力的基础。这是一个简单累加的Web service,它从客户端接受两个整数,然后返回两个数的和。
下图描述了Web service的高层体系架构:
图1。Web Service 1的高层体系架构
执行与接口哪个在先
构建Web services最通用的、最常见并被大多工具支持的方法是:从一个现有的执行中实现一个Web service接口。开发人员将写入如下代码:
public int Add(int x, int y) { return x+y; }
在ASP.NET的中,创建一个Web service非常简单,只要在代码中添加一个WebMethod属性,这种方法常被称为"执行优先"或者 "代码优先",因为通常用Web Service Description Language (WSDL)来描述的Web service接口源自于执行。
图2。执行优先的Web service开发
对于执行优先的Web service开发方法,首先你要为Web service写代码(参见图2#1)。编译过后,Web services框架将代码动态生成一个WSDL文件(参见#2)。当客户端需要Web service定义时,他们找到已产生的WSDL并创建基于此定义的客户代理(参见#3)。
例如,在ASP.NET中,WSDL可以由如下URL地址提供的一个执行被动态的创建:
http://hostname:port/Service1.asmx?WSDL
当.NET运行时发现请求中的WSDL参数时,它用带有WebMethod属性的代码映射来动态成生WSDL中的操作,用以描述底层的服务。
这种执行方法非常有效并且简单易行,但是也会产生一些问题,尤其是当Web service用于连接异构系统的情景下。例如:在执行优先的方法中很可能包括Web service中平台有关的类型。.NET记录集和Java向量都是平台有关的类型,这种类型在其他平台中不易被描述。这是因为通常在平台相关类型和XML中不存在单一的明确定义的映射。正是因为一个.NET客户端能够将XML元素识别为记录集,这并不意味着一个用Java写的Web service客户端可以做同样的事情。协同能力问题起因于此结果。
W3C XML模式标准定义了一系列内置的数据类型,其中包括各种不同长度的字符串,整型,布尔型,单精度,双精度,浮点型,时间型和其他类型。每种应用平台都支持一系列自己的数据类型。这些数据类型设置的交集定义了跨越不同平台的具有协同能力的类型。如果你一开始就运用XML模式类型,这将很容易映射到平台相关类型,但是如果你以平台相关类型作为开始,却很难映射为XML模式类型。例如,XML模式的整型,字符串型,布尔型,浮点型都能够很好的映射为.NET 或 Java相关的数据类型。然而,向量和哈希表是个别平台的产物,无法作为XML模式的官方类型。有关XML支持数据类型的详细信息请参阅XML模式数据类型详细规格说明书。
大多数Web services运行时(包括.NET Framework和WSDK内置的Web services运行时)都能够在XML模式的基本类型和具体平台的基本类型之间形成映射。在XML模式中的字符串可映射为.NET中的System.String,或是Java中的java.lang.String。运用XML的基本类型,就如同用这些类型构造数组和构造函数一样,可以构造出许多更加复杂的数据类型。运用XML 模式描述,这些复杂类型可以被高保真的从一个平台映射到另一个平台。为了在Web service中使用,这些数据类型也可以在WSDL文件中使用。
这就是"WSDL优先"设计的核心:用XML模式类型定义用于Web service中的数据类型,增加了你能够使用从一个平台映射到另一个平台的数据类型的可能性。
WSDL优先的方法有时也成为"模式优先"方法。即使这两个术语可以替换使用,事实上这两个术语间还存在细小的区别。本文提倡的是架构师和开发者在建造支持服务的底层代码前应该考虑构建使用WSDL定义的契约。为了构建WSDL文件,开发者即可以创建用于具体接口的XML模式定义,即"WSDL优先"方式,也可以使用他们内部应用领域已定义好的XML 模式,即"模式优先"方式。本文将采用"WSDL First"术语。
图3。WSDL优先的Web service开发
WSDL优先方法的挑战在于目前的开发工具没有扩展支持这项功能。这是非常可行的事实,但却不容易实现。Visual Studio提供了一个Schema编辑器和XML编辑器,但是却没有提供WSDL编辑器。Eclipse同样也没有提供WSDL编辑器。幸运的是两种环境都提供了从WSDL文件中产生除了客户代理程序之外的Web service框架代码的能力。
你可以用任意工具创建你自己的包含VI 和Notepad 的WSDL文件。不能直接用文本编辑,但可以利用诸如Altova的XmlSpy之类的专用工具来编辑,这种工具利用WSDL的设计器帮助我们完成任务。然而,正如许多开发者不能"think in WSDL."一样,这不是一个最终的解决方案。
关于这个问题的一个解决方案是运用执行优先的方法快速创建一个Web service接口的原型。我们用ASP.NET或IBM WSDK的动态WSDL产生特征创建一个临时的WSDL文件。随后我们可以开始利用WSDL优先方法进行开发,按照需要调整此接口,这个过程不断重复直到WSDL完成。
你可以在上面的图3中看到这个过程,这里有用WSDL优先方法创建Web services的三个高层步骤:
1. | 创建WSDL文档 |
2. | 执行WSDL文档 1. | 创建Web service | 2. | 创建Web service客户端 |
|
步骤2的A、B子步骤可以用你喜好的顺序执行。因为这两个子步骤都依赖于WSDL文档,所以唯一要注意的是:在执行A 、 B子步骤之前,WSDL文档必须被创建。
此部分剩下的步骤就是在WSDL 优先过程之后开发第一个Web service示例。本示例的全部源代码可以在本文附带的下载中找到。
从Visual Studio .NET(执行优先)中创建WSDL
在我们进入创建Web services的WSDL优先方法之前,我们先要关注一下Visual Studio .NET的执行优先开发模式。我们首先示范这种方法的原因是从头创建WSDL文件非常困难。越过开发过程的启动阶段,运用从执行优先方法中产生的WSDL文件是一个非常简单易行的替代方法。设想一下所有下列代码都手动键入的情景:
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:s0="http://example.org/"
targetNamespace="http://example.org/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<s:schema elementFormDefault="qualified"
targetNamespace="http://example.org/">
<s:element name="Add">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="x"
type="s:int" />
<s:element minOccurs="1" maxOccurs="1" name="y"
type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="AddResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="AddResult"
type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</types>
<message name="AddSoapIn">
<part name="parameters" element="s0:Add" />
</message>
<message name="AddSoapOut">
<part name="parameters" element="s0:AddResponse" />
</message>
<portType name="Service1Port">
<operation name="Add">
<input message="s0:AddSoapIn" />
<output message="s0:AddSoapOut" />
</operation>
</portType>
<binding name="Service1Soap" type="s0:Service1Port">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="Add">
<soap:operation soapAction="http://example.org/Add"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="Service1">
<port name="Service1Soap" binding="s0:Service1Soap">
<soap:address
location="http://localhost/NetWSServer/Service1.asmx" />
</port>
</service>
</definitions>
当然对于WSDL-wiz来说,这些担忧是微不足道的,但是对于我们剩下的工作将会长时间的沉溺于51页的WSDL详细规格说明中。因为写代码来创建一个Web service对于开发者来说是一种非常简单的方法,这就是我们要用执行优先开始我们工作的原因。
首先在Visual Studio .NET中创建一个C# ASP.NET Web Service项目,项目命名为WebService1WSDL.
图4。Visual Studio .NET新项目对话框
下一步,打开Service1.asmx代码。将注释掉的HelloWorld方法恢复并用如下方法替换之。
[WebMethod]
public int Add(int x, int y)
{
return -1;
}
图5。执行优先的Web service代码
构建此项目并保证没有错误。下一步,右击Service1.asmx,并将此页设置为开始页。你现在可以按F5观看Web service的测试页,如图6所示:
图6。Web service测试页
我们必须认识到ASMX文件是真实的Web service。你看到的页面源自于框架,它是为了证明Web service,并可以允许开发者不用手动创建客户端应用程序就可以测试Web service。这个测试的功能仅用于浏览本地页面,并且当向Web services输入复杂数据类型作为参数时此功能将不可用。处于安全问题的考虑,你要记得当你的Web service成为产品并开始发布时一定要禁用此测试页。
下一步,单击本页右上的Service Description链接。将打开另一个web页,展示给你的是服务生成的WSDL。WSDL生成功能一直是可用的,除非你专门将它禁用。将生成的WSDL保存在你本地的磁盘上,命名为WebService1.wsdl。
图7。框架生成的WSDL文件
现在你只是创建了一个WSDL文件,但还没有学习任何WSDL详细规格说明。
在此另外一个重要的提示是:由于我们从这个临时项目中生成了WSDL文件,而WSDL文档中的Web service定位很难编码指向这个临时项目。但这并不影响Web service,运用此WSDL文件的客户端将利用这个参数作为Web service的定位。因此重要的是在将此WSDL文件部署到web站点之前,你要替换这项值。一旦我们知道了Web service的真实位置我们将随后替换这项参数。
如果你忘记替换此项地址,并且客户端应用程序已经创建,你还可以通过修改客户端参考指向的地址来修改这项参数。.NET 和WebSphere Web service客户代理都允许设置一个URL属性。当从开发环境移植到产品环境时,此项功能也非常有用,因为产品环境中服务执行的终结点是唯一要改变的事务。
既然我们创建Web service如此简单,我们生成WSDL文件也就无需过多的调整。下一步就是创建真实的.NET Web service.
实现.NET Web Service(WSDL优先)
运用先前步骤生成的WSDL,我们将创建一个新的.NET Web service。
为了将WSDL file转化为源代码文件,我们将利用一个称为wsdl.exe控制台应用程序来产生代码。此工具将解析WSDL文件和其他一些附加文件来产生单一的源代码文件,源代码文件中包含执行Web service所需的所有类、方法、类型。Wsdl.exe将随着Visual Studio .NET 2003 (和.NET SDK)一起被安装。运用此工具,你首先需要打开Visual Studio .NET 2003命令提示控制台,默认情况下,此项位于开始菜单>>程序>> Microsoft Visual Studio .NET 2003的Visual Studio .NET工具。一旦打开,你便可以在以前保存的WSDL文件中操纵命令提示。
执行下列命令可以使得wsdl.exe产生Web service源代码文件。
wsdl.exe /server WebService1.wsdl
图8. Visual Studio .NET 2003命令提示控制台执行wsdl.exe
从上图可以看出:有效的输出一个消息表明Service1.cs被成功创建。这个文件是我们构建Web service的起点。wsdl.exe产生的文件仅仅是我们想要执行的方法模板;因此,为了保证无误的工作,文件必须被修改。当采用/server选项执行wsdl.exe时候,当前wsdl.exe命令始终产生的是Web service的一个抽象类。我们通过消除abstract关键字和为Add方法添加执行体来将抽象类转变为具体类。我们还要将类放入WebService1的命名空间中。目标代码如下所示:
namespace WebService1
{
///
[System.Web.Services.WebServiceBindingAttribute(Name="Service1Soap",
Namespace="http://tempuri.org/")]
public class Service1 : System.Web.Services.WebService {
///
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute(
"http://tempuri.org/Add", RequestNamespace="http://tempuri.org/",
ResponseNamespace="http://tempuri.org/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=
System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public int Add(int x, int y) {
int result;
result = x + y;
return result;
}
}
}
你可能很奇怪,为什么子类成为了抽象类,而不是将它转换成一个具体类。这里有一个很好的解释。wsdl.exe工具产生代码,代码由属性修饰,这些属性用于.NET的XML序列化和Web services 运行时,它们将对象映射为XML,又将XML映射为对象。例如,对于产生的XML文档,我们示例中的一个属性运用了http://tempuri.org命名空间。这些属性并没有被子类继承。因此子类是一个抽象类,我们需要剪切和粘贴具体类中的所有属性。
并不是手动的复制所有的属性,而是非常简单的直接编辑文件。当然这就意味着如果WSDL发生变化,你就需要为WSDL文件重建源代码。如果重建过程出现闪失,这个过程将会毁掉所有现存的代码。你就必须从旧文件中手动拷贝Web service执行代码到新文件中。
现在我们已经准备好了Web service源代码,是时候开始创建我们的Visual Studio解决方案了。创建一个新的Visual Studio .NET C# ASP.NET Web Service项目并命名为WebService1。
一旦你创建了项目,复制早期创建的Web service执行代码Service1.cs到Visual Studio产生的Web service文件目录下。通常是c:\inetpub\wwwroot\WebService1目录。
图9。Windows资源管理器显示的Web service项目文件
Web service的示例Service1.asmx作为Visual Studio项目向导的一部分产生。因为wsdl.exe命令仅产生了执行代码模板,而没有产生入口点文件,我们希望重用VS产生的Service1.asmx,而不是自己创建。然而,Service1.asmx已经产生了相应的源文件。一个简单的办法是通过删除VS创建的执行代码和重命名执行代码来将ASMX与执行代码合并。在你做这些工作前,确保Service1.asmx和Service1.asmx.cs没有在Visual Studio中打开。然后,删除当前的Service1.asmx.cs,并将Service1.cs改名为Service1.asmx.cs。
为了校验代码的移植工作,选择Visual Studio解决方案资源管理器中的Service1.asmx,并且点击视图菜单,然后点击代码。你将看到我们以前在Visual Studio .NET 中修改过的Add方法执行的模板代码。
最后,为了测试Web service是否工作正常,右击Service1.asmx并点击Set As Start Page。然后转到Debug菜单,单击开始创建项目并在浏览器中打开Service1.asmx。用测试页校验你的Web service工作是否正常。
图10. Web Service添加测试页
图11.等待Web service12加45的应答信息
为了掩饰.NET Web service,我们需要返回到原始的WSDL文件中做些微小的变化。正如以前提到的,在我们临时的Web service项目中,WSDL文档是当前的切入点。现在我们已经完成了真实的Web service,我们可以修改定位参数指向这个Web service。你可以通过打开原始的WSDL文档,替换soap:address元素的location属性,将它指向新Web service地址来完成上述工作。新的soap:address元素如下所示:
<port name="Service1Soap" binding="s0:Service1Soap">
<soap:address location="http://localhost/NetWSServer/Service1.asmx" />
</port>
图12. WSDL文件中Web service的定位被修改
以上总结了运用WSDL优先的方法构建.NET Web service的过程。接下来,我们将构建使用.NET Web service的 WSDK Web service客户端。
实现WSDK Web Service客户端
现在我们已经实现了一个Web service,到了该创建一个使用Web service客户端的时候了。因为本文讨论的是有关协同工作能力的问题,我们将运用一个运行在IBM WebSphere应用服务器上的JSP页来使用.NET Web service。
启动Eclipse,创建一个新的Dynamic Web 项目,并将项目命名为WebServiceClient1,将EAR 项目文件命名为WebServiceClient1Ear。
图13. Eclipse显示的WebServiceClient1项目
接下来,在WebServiceClient1项目中添加WSDL文件。你可以通过在Eclipse导航条直接将文件拖拽到项目中的方式来完成上述工作。
现在我们要为Web service创建一个java代理。当向项目添加参数时,其过程类似于在Visual Studio .NET中创建一个代理。WSDK工具将创建一系列java文件,这比直接操控网络流更容易调用Web service。由于我们已经在项目中添加了WSDL文件,所以可以通过右击WSDL文档,在出现的Web Services菜单中点击Generate Client来创建代理。上述步骤将创建WSDL到 Java Bean 的代理向导,如下图14所示:
图14. WSDL到Java Bean代理向导
在第一个对话框中,选中Test the generated proxy选项,将会产生测试JSP页(类似于当在Visual Studio中创建Web service时从Service1.asmx中产生测试页的过程),测试页用来验证代理类的产生。向导的其余部分采用默认选项,最后点击完成。
在Eclipse完成所有必须文件的创建后,如下的测试页被显示在Eclipse的主窗口中。
图15. Eclipse IDE显示测试JSP页面
单击方法窗口格中的add(int,int),在Inputs窗口格中输入两个数字。将会看到两个数字的和出现在底端的Result窗口格中。在这些场景之后,JSP页面正在调用早期被WSDK Web service 向导创建的Web service代理类,此代理类又调用了.NET Web service。由于我们改变了WSDL文档中Web service的定位参数,因此Java客户端可以准确的定位到先前在第二步中创建的Web service上。如果显示的两个数之和结果正确,此成功将证实Java代理创建正确,并且已经能够与.NET Web service对话了。
另一个验证服务和客户端连接的方法是在Visual Studio .NET的Web service代码中设置一个断点,并以调试模式运行服务。在Java端,一旦你在JSP页面中执行了加法功能,你将看到Visual Studio .NET停止了Web service的执行,并在你设置的断点上产生中断。
本章,我们验证了WSDL 产生的Java代理类工作是否正常,我们还运用WSDK向导产生的测试页从JAVA中调用了.NET Web service。由于一些正常,这就表示我们完成了Web Service 1中.NET Web service和Java Web service客户端的演示。虽然我们没有描述创建.NET Web service客户端和Java Web service服务器端的细节步骤,本文附带的示例代码包含了服务器端和客户端,.NET 和Java任意组合的执行。
Web Service 2:等级和报告
第二个例子将在第一个例子的基础上创建Web service,此Web service将运用更加复杂的数据模式。这个示例的目标是展示当运用复杂数据类型时.NET 和 WebSphere的协同工作能力。在本示例的数据模式中,将结合使用复杂类型,简单类型,枚举类型,约束类型,数组以及由标准XML模式类型中继承的其他类型。由于复杂性的增加,两个平台的差别和开发协同Web services的问题将在本示例中呈现出来。
情景
Stuff Sellers公司对不同的商业交易出售不同的产品。每项交易都允许提交他们所卖产品的评论。Web Service 2提供了一个等级服务的场景,允许用户提交一份带等级的报告,或者允许用户获得一份带等级的报告列表,等级通过一个数字来表示。在这种情况下,报告可以看成为类似评论的东西,对评论的总结产生了最终的等级。
数据模式
下图描绘了数据模式的高层元素。
图16。Web Service 2数据模式的主要元素
最高层的元素是Ratings。每个Ratings元素包含一列ReportSet元素(压缩为ReportSetArray类型)。每个ReportSet元素包含一列Report元素(压缩为ReportArray类型)。所有的这三个高层元素都是从MyBase类型继承而来的数据类型。有关本数据模式更详细的XML模式定义请参阅随范例下载的WebService2SharedTypes.xsd文件
最高层的元素是Ratings。每个Ratings元素包含一列ReportSet元素(压缩为ReportSetArray类型)。每个ReportSet元素包含一列Report元素(压缩为ReportArray类型)。所有的这三个高层元素都是从MyBase类型继承而来的数据类型。有关本数据模式更详细的XML模式定义请参阅随范例下载的WebService2SharedTypes.xsd文件
在很多情况下,数据模式先前就已经定义好了,并独立存在于Web service执行和接口之外。这种情况将在当你被指定要创建一个基于现有系统的Web service时会发生。不管你是否创建一个模式或者提供给你一个现存的模式,数据模式都应该被自解释的XML Schema XSD文件所描述,并且允许数据模式的模块化和重用。
如下所示的类图描述了此Web service数据模式中定义的XML Schema。在相同的代码中,模式被定义在WebService2SharedTypes.xsd文件中。每个平台数据模式(XML Schema文件)产生的代码都应该表示为类似于下图的类结构。
图17. Web Service 2中数据模式的类图
Web Service定义
在第一个Web service中,我们运用.NET框架创建了初始的WSDL文件模板。因为我们的Web service非常简单,所以这是我们创建WSDL的唯一步骤。不幸的是,此处底Web service不像第一个示例那么简单,所以需要一些手动的调整。为了维持协同能力,我们要对WSDL文件模板做如下调整:调整数据模式,改变命名空间,为portTypes类型创建正确的消息。
Web service 的WSDL文档定义了两个操作:GetRatings和SubmitReport。如果提供的ID与给定的等级匹配,GetRatings将返回一个Ratings类型数据。SubmitReport操作用于客户提交一个整合Ratings 和 ReportSet类型的新报告。有关WSDL定义的这些操作,你可以在随范例下载的WebService2.wsdl文件中看到。
这里提供底两种方法将XML Schema定义包含在WSDL文件中:你可以定义模式内嵌在WSDL文件中,或者可以通过运用xsd:import元素在WSDL文件中定义XML Schema。由于内嵌定义是WSDL文件的一部分,因此这种方式易于维护。然而,由于数据模式描述的是数据而不是Web service接口,并且有时还需要运用单独的web service接口,这就使得将两个定义分割到两个独立的文件中这种方法更符合逻辑。如果你的Web service非常简单不需要复杂的数据类型,那么内嵌模式更适合(正如Web Service1一样),但是在大多数Web services中,都需要从Web service定义中分割数据模式。
在本Web service中,我们使用xsd:import方法定位外部的XML Schema文件,即WSDL文件WebService2.wsdl中的WebService2SharedTypes.xsd文件。在WSDL文件中,如下代码所示:
<types>
<xs:schema targetNamespace="http://example.org/">
<!-- Import the Shared Types -->
<xs:import namespace="http://example.org/sharedtypes"
schemaLocation="WebService2SharedTypes.xsd"/>
<!-- Import the Message Parameters -->
<xs:import namespace="http://example.org/interface"
schemaLocation="WebService2Interface.xsd"/>
</xs:schema>
</types>
. . .
执行
在.NET中创建Web service代码模板,以如下参数运行wsdl.exe。
wsdl.exe WebService2.wsdl WebService2Interface.xsd
WebService2SharedTypes.xsd
我们注意到wsdl.exe需要输入WSDL文件,并且所有包含的XSD文件都被一起列入命令行中。当向WSDL引入XSD时,很可能需要提供一个schemaLocation属性。根据WSDL的详细规格说明,这个属性是模式定位的线索。这个线索不一定能被解释WSDL文件的工具所识别。在这种情况下,wsdl.exe就不能利用schemaLocation线索,因此外部的模式文件就必须在命令行中详细列出。另一方面,IBM WSDK工具需要利用schemaLocation线索并在列出时直接装载这些文件。
要注意的一个重要细节是MyBase元素的ID被类型xsd:int定义,并且包含minOccurs=0的属性。MyBase 的XML Schema定义如下所示:
<xs:complexType name="MyBase">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="ID" type="xs:int"
nillable="true" />
</xs:sequence>
</xs:complexType>
当minOccurs=0时,表明ID属性可以在XML文档中省去。不过这将导致.NET平台的一个问题:在.NET中xsd:int映射为Int32,Int32是一个数值类型,数值类型不能为空。这就意味着,由于Int32的值必须是有效数值,所以无法决定是否设置ID属性。.NET框架通过创建另一个Boolean类型的IDSpecified变量来解决这个问题。此变量由.NET XML序列逻辑来检查,用以决定ID变量是否应该被设置,其本质就是给ID赋上NULL/not NULL的值。因此无论是否想访问ID变量,你都首先要检查或设置IDSpecified变量。关于这种运用模式的更多详细信息,请查阅XmlIgnoreAttribute类的MSDN文档。
如下所示是C#表示的MyBase类型:
[System.Xml.Serialization.XmlTypeAttribute(Namespace=
"http://example.org/sharedtypes")]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(Report))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(ReportSet))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(Ratings))]
public class MyBase
{
public int ID;
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool IDSpecified;
}
当运用WebSphere示例时,此问题不会产生,因为xsd:int包含minOccurs=0,WSDK工具产生java.lang.Integer类型的变量来代替原来的int Java类型。java.lang.Integer类型是一个参考类型,这种类型可以赋值为NULL来表示没有被设置。运用WSDK中提供的工具,得到如下的用Java 代码表示的MyBase类型:
public class MyBase implements java.io.Serializable {
private java.lang.Integer ID;
public MyBase() {
}
public java.lang.Integer getID() {
return ID;
}
public void setID(java.lang.Integer ID) {
this.ID = ID;
}
}
另一个明显的区别是当比较XML Schema产生的C#代码和相同schema产生的Java代码时,在C#代码中包含代码属性。正如我们以前所说的那样,运用.NET 中XML序列器能够将类的实例映射为XML。Java同样也需要类似的"元数据"。在WSDK的Web services运行时中,这个元数据被独立存储,并且在XML文件中定义类型映射。关于更多详细信息请参阅WSDK文档。
另一个有趣的问题是:如果你检查一个由.NET工具或者是WSDK工具生成的类,你会发现产生的数据类型不是你写的,因为作为一个开发者,你可能没有考虑到协同能力的问题。检查WSDK产生的Ratings.java类,排除掉一些事务处理代码,如下所示:
public class Ratings extends org.example.MyBase implements java.io.Serializable {
private java.lang.String description;
private int confidenceLevel;
private java.util.Calendar expiration;
private org.example.ReportSetArray allReports;
public Ratings() {
}
public java.lang.String getDescription() {
return description;
}
public void setDescription(java.lang.String description) {
this.description = description;
}
public int getConfidenceLevel() {
return confidenceLevel;
}
public void setConfidenceLevel(int confidenceLevel) {
this.confidenceLevel = confidenceLevel;
}
public java.util.Calendar getExpiration() {
return expiration;
}
public void setExpiration(java.util.Calendar expiration) {
this.expiration = expiration;
}
public org.example.ReportSetArray getAllReports() {
return allReports;
}
public void setAllReports(org.example.ReportSetArray allReports) {
this.allReports = allReports;
}
}
对于简单的数据成员,例如int和string类型,它们可能由任何设计者手动创作:依照JavaBean的协定,getters和setters被预先封装为私有成员。随后差别出现了,数值被Calendar处理,而不是一个java.util.Date。并且,数组被封装在自定义类中,通过一对getter/setter存取。这个类不需要你自己写,这对于协同能力的实现有更多底好处。你可以使用.NET工具书写同样结构的代码。
为了构建两个Visual Studio项目:一个客户端,一个服务器端,通用步骤已经在上述的Web Service 1部分描述过了。我们同样也使用WSDK建立两个WebSphere项目。所有的这些客户端和服务器端都能互相协同工作。编译运行随此部分下载的示例中的Visual Studio项目和Eclipse项目。执行之前请先阅读随示例下载的Readme。
本示例研究了在一个协同工作的Web service中复杂数据类型的应用。W3C XML Schema在定义消息类型和数据元素的工作中担当了重要角色。本部分讨论了如何为复杂数据类型开发XSD,如何使用WSDL文档中的XML Schema。本部分还列举了一些所知的边缘事例,例如,.NET中值与参数的区别,这种区别将在XML序列化时体现。
在下一个示例中,我们将以本示例作为扩张,研究运用扩展数据类型的协同工作能力。
Web Service 3:产品搜寻
大多数Web services都是使用固定的数据模式。——这就意味这,通过通讯线路发送的数据类型在设计的时候就是可知的。但是有些时候,一个静态的数据模式不能满足应用程序的需求。请考虑如下的商业情景。
情景
正如Web Service 2提到的,Stuff Sellers向客户和其他商业机构出售产品。由于公司出售各式各样的产品,管理者不得不求助我们为他们建立一个Web service,用以使得从数据库中检索产品的工作更加容易。搜索通过互联网商铺间接被消费者使用,并直接被其他商业机构使用。
管理者选用Web service用以支持下列三个需求:
1. | 允许动态数据。因为Stuff Sellers经常向数据库中添加新产品类型,Web service定义应该足够灵活以至于不用打断在线客户的交易就能添加新的产品类型。 |
2. | 支持基本处理。从Stuff Sellers搜索产品的公司可能仅对产品的某几个属性感兴趣。例如,折扣店可能仅会搜索低于50美分的产品。Web service应该能够返回这样的数据,并允许客户对结果做简单的检查。 |
3. | 可扩展。Stuff Sellers将来可能需要修改Web service,并且在最小限度影响现有客户的基础上让Web service支持新特性。 |
除了这些需求,管理者希望Web service接口越简单越好。具体来讲,Web service应该只有一个单一的入口点。
观察Stuff Sellers目前出售的产品。我们发现所有产品至少有如下属性:姓名,描述,价格,SKU。这些属性是我们所有产品的基本特性。例如一个DVD电影有区域编码,视频格式,语言,版本数据等属性。一本书有作者列表,出版社,ISBN,出版日期等属性。因此基本产品类型将要包括所有产品类型的公用属性,并允许有关特定产品类型属性的扩展。
数据模式
如下的类图是Web Service 3数据模式的表示。
图18. Web Service 3数据模式的类图
搜索结果的XML Schema类型定义(在WebService3SharedTypes.xsd中),如下所示:
<xs:complexType name="SearchResult">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="SKU"
type="xs:string"/>
<xs:element minOccurs="1" maxOccurs="1" name="Price"
type="xs:decimal" />
<xs:element minOccurs="1" maxOccurs="1" name="Name"
type="xs:string"/>
<xs:element minOccurs="1" maxOccurs="1" name="Description"
type="xs:string" />
<xs:element minOccurs="1" maxOccurs="1" name="ProductType"
type="xs:string" />
<xs:any minOccurs="1" maxOccurs="1" processContents="lax" />
</xs:sequence>
</xs:complexType>
你可以看到,SearchResult是父类型,表示了能被Web service找到的所有产品。另外,SearchResult还包含xsd:any元素,相当于通配符的功能。在特定场所下此模式有效的XML文件可以包含所有的XML元素。为了我们的目的,xsd:any元素将包含一个产品属性类型,此类型可以被Web service返回。我们在WebService3ExtendedProperties.xsd中定义了三个这样的产品属性类型:DvdProperties, BookProperties和CDProperties。实际上,客户应用程序通过检查SearchResult存取通用类型,并通过检查包含在产品细节属性类型中的成员变量来存取产品扩展属性。
代替用模式中的xsd:any匹配任意XML元素的方法是使用模式中的字符串元素,这个元素将包含动态产生的XML。运用一个字符串类似于运用通配符的方法。其不同之处在于传输时XML包含的字符串被忽略,这对于XML解析器来说不可识别。这并不是我们所希望的。对于整合XML文档中的动态XML来说它是一个清洁器,而不是作为字符串元素被忽略掉。任何一种方法,都需要一些额外的工作,在发送方产生XML,或是在接受方解析XML。
Web Service定义
正如第二个示例所述一样,此Web service 的WSDL文档被分割成了两个文件:WebService3.wsdl 和WebService3SharedTypes.xsd。WebService3.wsdl包含定义Web service的声明,WebService3SharedTypes.xsd是一个XML Schema文件,包含Web service要用的数据类型。如下示例捕获了Web service客户端返回的SOAP消息。
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<SearchResponse xmlns="http://example.org/sharedtypes">
<SearchResult>
<SearchResult>
<SKU>B05502HB9I</SKU>
<Price>14.99</Price>
<Name>Spain's History</Name>
<Description>Short documentary on the history of the
Spain.</Description>
<ProductType>DVD</ProductType>
<DvdProperties xmlns="http://example.org/resulttypes">
<Region>EUROPE</Region>
<Format>PAL</Format>
<Language>Spanish</Language>
<ReleaseDate>2000-05-14</ReleaseDate>
</DvdProperties>
</SearchResult>
<SearchResult>
<SKU>A04D5E87RJ</SKU>
<Price>20.00</Price>
<Name>Spain's History</Name>
<Description>Companion coffee table book to the documentary
"Spain's History".</Description>
<ProductType>Book</ProductType>
<BookProperties xmlns="http://example.org/resulttypes">
<Authors>
<Author>Mark Person</Author>
</Authors>
<Publisher>BookPub Central</Publisher>
<ISBN>0459756212</ISBN>
<PublishedDate>2003-08-08</PublishedDate>
</BookProperties>
</SearchResult>
</SearchResult>
</SearchResponse>
</soap:Body>
</soap:Envelope>
这里还有第三个文件,WebService3ExtendedProperties.xsd,此文件没有导入到WSDL中,但是对Web service产生应答以及对客户解析应答来说是个关键。此文件包含了数据动态部分的定义:产品类型的扩展属性。
将产品类型和用于Web service的类型分离的好处是不修改接口就可以扩展产品类型。最终使得Stuff Sellers可以扩展他们的业务,开始其他类型产品的买卖。因为搜索结果将包含这些新产品,所以以简单的方式添加新产品是目前最紧要的需求。基于我们的设计,对于扩展Web service执行用以返回新类型和扩展WebService3ExtendedProperties.xsd中定义的数据模式来说支持新类型是件简单的事情。发布的基于Web的 新XSD文件,让消费者知道变化是所需的最后步骤。WSDL文件不需要任何变化。
Web service的客户并不总希望运用扩展的属性或简单的通过扩展属性选择其他能忽略扩展属性的服务。在运行时,这些客户不需要反序列化XML到对象。例如,如果一个应用程序是为了仅通过价格过滤产品,那么他们就不会介意哪类型的产品被返回。在这种情况下,客户仅需要检查SearchResult类型基础的属性价格,并能忽略掉扩展的属性。
对于xsd:any的应用,Web service在不断开现有客户连接情况的下,易于添加新特性。新的Web service客户可以运用新的产品类型,同时现存的应用程序可以轻松的忽略掉新产品类型。甚至现存产品类型被删除了,现存的Web service客户仍然能够正常工作,因为他们并没有执行与旧产品有关的代码。这个设计提供了世界上最好的东西,新应用程序的返回信息可以被扩展,同时又允许现有的应用正常工作。
执行
XML和相应对象事例的转化被称作"XML 序列化", 或 "XML绑定".对于Web service调用的两参数之间的转化过程,通常由Web services运行时自动完成。 XML通过通讯线路传送Web service请求或应答信息。然而,当运用schema扩展时,此扩展没有在WSDL(或者其导入的XSDs)中定义,XML序列化和反序列化必须被手动完成。.NET提供了这样的工具和设计接口。
IBM WebSphere没有提供手动执行XML序列化的公共接口。Java客户端和服务器端需要一个附加功能来执行Java到XML的绑定。JAXB API提供了这样的附加功能,JAXB API是Sun的JWSDP的一部分。安装JWSDP将附带给你一个JAXB编辑器,编辑器可以从XML Schema中产生Java类,类似于.NET 中xsd.exe的用途。运用类表示数据类型比直接操作XML元素简单的多。在JAXB中,产生的数据类型类还要从与XSD一致的XML文件中做marshalling" , "serializing","unmarshalling" 或"deserializing"工作。
.NET框架SDK还包括绑定XML数据到.NET类的工具和框架。Xsd.exe工具解析XSD文件用以创建相应的源代码文件,此文件包含数据类型定义的类。在运行时,应用程序可以用类的System.Xml.Serialization命名空间从XML流或vice-versa中创建一个对象图。
例如,在编译时,从WebService3ExtendedProperties.xsd模式中产生C#类,如下代码所示:
xsd.exe /classes WebService3ExtendedProperties.xsd
然后,在运行时,从文件中产生对象图,如下代码所示:
FileStream fs = new FileStream(path, FileMode.Open);
XmlSerializer s= new XmlSerializer(typeof(BookPropertiesType));
BookPropertiesType props;
try {
props= (BookPropertiesType) s.Deserialize(fs);
}
finally {
fs.Close();
}
通常情况下,对于Web services接口中运用的数据类型,产生数据类型类和执行序列化的步骤都是自动执行的:前者通过wsdl.exe产生或由Visual Studio中的"Add Web Reference"产生,后者通过.NET的web services运行时产生。当你向web service传输一个参数时,参数被自动序列化为XML,用以通过网络传输。在这里对于产生类来说xsd.exe的用途是必须的,因为WebService3ExtendedProperties.xsd模式并没有明确的包含在web service接口定义中。
什么是运行时的序列化?当分析一个模式时,xsd.exe将xsd:any元素映射为XmlElement类型字段。通过修改生成的类,将类型字段改为System.Object而不是System.Xml.XmlElement,并且以XmlElementAttribute属性来修饰字段,我们还可以通过框架将XML数据映射为具体.NET的数据类型,而不是通用的XmlElement。例如,在本片断中,任何字段都可以映射成为三个扩展属性之一。
[System.Xml.Serialization.XmlElementAttribute(ElementName="DvdProperties",
Type=typeof(NetWSServer3.DvdPropertiesType),
Namespace="http://example.org/resulttypes")]
[System.Xml.Serialization.XmlElementAttribute(ElementName="BookProperties",
Type=typeof(NetWSServer3.BookPropertiesType),
Namespace="http://example.org/resulttypes")]
[System.Xml.Serialization.XmlElementAttribute(ElementName="CDProperties",
Type=typeof(NetWSServer3.CDPropertiesType),
Namespace="http://example.org/resulttypes")]
public object Any;
对于产生类的修改,.NET运行时将自动的从XML序列化产品属性映射为对象类型或是相反过程。没如果有这个能力,开发者就要显式的完成类到XML的序列化。实际上,这就是WebSphere对于扩展属性类型的处理方法。(关于细节参阅示例代码)
开发此示例的同时,有关于将ProductType设计为枚举类型还是字符串类型的考虑。枚举类型的好处是不同类型可以被清楚的定义,并且不易混淆。然而,最后决定并不是设计为枚举类型,这是因为可扩展的需求:我们需要在不打扰现有客户的情况下方便的添加和删除现有产品类型。如果ProductType被定义为枚举类型,未来产品类型通过老客户端时,就会产生中断。因此用字符串类型代替了枚举类型,因为这种方式保证了在不打扰现有客户工作的基础上灵活的扩展的产品线。
对于Web Service 2,数据类型通过工具产生将无法与开发者所写代码匹配。然而,在这里,强调的是以WSDL作为开始和产生代码协同工作能力的关键优势。
在Web Service 2中,我们列出了本文介绍的运用Visual Studio和 WebSphere web services SDK创建客户端和服务器端项目的大概步骤。在这里,我们要强调的是,最终客户端和服务器端完全实现了协同工作。好的,这已经足够描述问题了。编译和运行下载示例中的Visual Studio项目和Eclipse项目,观察本部分Web Service 3的可扩展性。
Web Service 3显示了复杂数据类型的运用,在WSDL中静态包含如同动态包含一样。对于扩展类型的支持允许以最小的变化,灵活的扩展和修改接口,此接口用于Web service 和 Web service 客户端。
结论
本文的三个Web services示例显示,运用复杂数据类型创建协同工作的Web services完全可能。简单的方法是通过开发工具——"执行优先"——会导致协同工作能力的挑战。然而,通过定义Web service接口优先的方法,许多协同工作能力的缺陷都可以避免。虽然我们仅仅展示了.NET 和WebSphere的"WSDL优先"方法,但是图中展示的观念可以应用于所有平台的协同工作中。
手动创建WSDL的工作并不容易,本文同时也展示了运用包含在Visual Studio .NET 和WSDK的原型工具开发和提炼WSDL文件W3C XML Schema定义的方法。
最后,本文提供了对创建协同能力和扩展Web services的方法中有关缺陷的提示。有了这些创建协同工作Web services的方法,我们可以最终实现所有系统一致存取,平台架构无关的梦想。
如下列出了本文的推荐文章和回顾提示列表。
推荐/提示
工作在WSDL文档中
1. | 当手动编制WSDL时,要注意当前命名空间的内容。表示命名空间的字符串必须同所有对此命名空间的引用一致。 |
2. | 如果从或者到XML的映射没有明确定义,Web service必须返回复杂数据类型,就要考虑创建自己的数据类型来表达数据。 |
3. | 为了提高模块化和重利用性,运用XSD作为输入而不是嵌入到模式定义中。参见Web Service 2和 Web Service 3 示例。 |
4. | 小心XML Schema定义中的数据类型的可选属性。他们中的一些可以在执行代码产生时改变。参考Web Service 2中的ID 定义。 |
5. | Web Services协同工作能力组织是一个官方组织,它负责提高跨越所有平台和语言的Web services的协同能力。该组织创建了对协同能力的详细规格说明,被成为WS-I基础平台,该组织还提供了使WSDL 文件基于标准的辅助工具。 |
6. | 当Web service产生异常时,SOAP 消息中的SOAPFault元素被返回。典型情况下Web service框架将捕获SOAPFault并返回自己的异常类。在.NET框架中,SOAPFault被捕获并封装在System.Web.Services.Protocols.SoapException中。在WebSphere中,com.ibm.ws.webservices.engine.WebServicesFault是抛出的异常。有关错误的附加信息可以通过访问提到的异常类的属性获得。 |
7. | 所有XSD复杂类型都被翻译成类。因为Java当前还不能支持枚举类型,在相应的Java类中枚举类型的值被翻译成公共静态的常数。 |
8. | XSD模式的一些特性不能在现有的一些平台中很好的表现。一个示例是XSD中的无符号整数类型。虽然.NET提供了无符号类型,但是Java没有提供。因此在协同能力的Web services中运用无符号整数类型是不推荐的做法。 |
9. | 当工作于边界条件中时,运用数组是灵活的做法。在.NET中,如果一个空的数组类型被序列化,那么仅仅头XML元素被创建。如果空数组被序列化,那么它将完全被忽略并且没有任何XML元素被创建。相反,Java可以序列化上述两种情况下的XML元素。差别是对于为空情况的处理,WebSphere中的Web services运行时将用xsd:nil=true属性标记XML元素,以表明数组为空。 |
10. | 当WebSphere客户端反序列化一个空的.NET数组时候,会产生一个空值的数组。如果WebSphere客户端反序列化一个为NuLL的.NET数组,将会抛出java.lang.NullPointerException异常 |
11. | 当.NET客户端反序列化一个空的WebSphere数组时,将产生一个长度为0的数组。当.NET客户端反序列化一个为NULL的WebSphere数组时,将设置数组参数为NULL。 |
工作在Wsdl.exe中
当WSDL文件参考其他文件时(如XSD文件),你必须为wsdl.exe明确的提供这些文件的定位。为了安全起见,wsdl.exe不能自动从WSDL文件的schemaLocation参数中装载文件。例如,如果你要产生如Web Service 2所示的代码,你需要执行如下命令:
wsdl.exe WebService2.wsdl WebService2Interface.xsd
WebService2SharedTypes.xsd
关于Web Service 2的更多信息请查阅本文。
默认情况下Wsdl.exe通过C#模板代码产生。如果你更喜欢另一种语言(例如VB.NET),请加入如下/l后选项代码:
wsdl.exe /l:vb WebService1.wsdl
当为Web service产生源文件时(运用/server选项),工具将随着WSDL文件产生一个抽象类。这里推荐你直接修改此文件而不是在产生的文件中创建子类。关于本话题的更多信息请参阅Web Service 2。
Visual Studio .NET 2005将支持在IDE中直接从WSDL产生模板源文件。除此之外,如果WSDL文档发生变化,模板文件也要重新生成,IDE将采取如下方法处理:旧模板中现存的代码被新模板沿用。
在Visual Studio.NET中工作
当在Visual Studio.NET中创建一个Web服务应用程序的时候,创建好的项目自动提供了一个测试页面,这个页面上显示了什么时候这些Web服务通过浏览器被处理了。由于我们开发Web服务的时候,使用了WSDL第一种方法,因此在这里推荐你关闭在公开的位置自动生成WSDL和发布自己WSDL的功能。为了关闭自动生成测试页面和WSDL,添加下面的代码到你项目中Web.config文件中的<system.web>元素:
<webServices>
<protocols>
<remove name="Documentation" /> </protocols>
</webServices>
除了使用wsdl.exe方法创建一个Web服务的代理类,你也能够在Visual Studio.NET中使用一个内置的工具,更加友好的方法创建代理类。,添加Web引用对话框会询问你指向一个WSDL文件,然后就会创建一个代理类。在这个操作的背后,对话框本质上还是在后台调用了wsdl.exe处理WSDL文件。
不幸的是,在创建一个客户代理的时候,会有一个bug。如果你使用VS.NET2002添加Web引用命令指向一个WSDL文档,其实是使用了xsd:import。在这种情况下,通常使用wsdl.exe来生成客户代理。这个bug在VS.NET2003中已经被修复,在VS.NET2003中,它将找到所有被包含的文件然后再创建客户代理类。
通过Eclipse创建WSDL文件
通过WSDK提供的工具,Eclipse中的Web服务功能跟Visual Studio中的功能是类似的。在Eclipse中,你需要创建一个Java Bean或者EJB,同时,把它们作为一个Web服务的模板。Eclipse中也有命令行功能,你能够使用它们创建Web服务模板文件。你能够在Eclipse中找到更加详细的描述如何完成这些操作的文档。
感谢:
感谢微软Simon Guest先生能够出色的完成检查工作并给予反馈。同时感谢Vertigo软件的Neil Chopra和Mike Hanley先生的测试工作,以及在论文观点上的一些帮助。
有用的链接
转到原英文页面