﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-HERE WE GO!!!-随笔分类-Web Service</title><link>http://www.cnitblog.com/xiaoyaocao/category/2083.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 26 Sep 2011 04:29:23 GMT</lastBuildDate><pubDate>Mon, 26 Sep 2011 04:29:23 GMT</pubDate><ttl>60</ttl><item><title>用JAX-RPC开发Web服务: Servlet作为Web服务端点</title><link>http://www.cnitblog.com/xiaoyaocao/archive/2006/09/28/17455.html</link><dc:creator>逍遥草</dc:creator><author>逍遥草</author><pubDate>Thu, 28 Sep 2006 10:43:00 GMT</pubDate><guid>http://www.cnitblog.com/xiaoyaocao/archive/2006/09/28/17455.html</guid><wfw:comment>http://www.cnitblog.com/xiaoyaocao/comments/17455.html</wfw:comment><comments>http://www.cnitblog.com/xiaoyaocao/archive/2006/09/28/17455.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/xiaoyaocao/comments/commentRss/17455.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/xiaoyaocao/services/trackbacks/17455.html</trackback:ping><description><![CDATA[
		<blockquote>本文是J2EE Web服务开发系列文章的第三篇，本文将首先介绍JAX-RPC基本构架，然后重点讨论把Servlet作为JAX-RPC Web服务端点时的开发步骤，以及各个步骤中要使用的工具和编程技巧。在内容的组织上，仍然结合本系列文章第一篇（《用JAXM开发Web服务》）中的案例，一步步引导读者使用JAX-RPC开发Web服务。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>阅读本文前您需要以下的知识和工具：</p>
		<ul>
				<li>JavaTM Web Services Developer Pack 1.1，并且会使用初步使用； 
</li>
				<li>辽倩崾褂靡恢諩JB容器来开发、部署EJB，并且了解怎么在客户端访问EJB组件； 
</li>
				<li>对Apache axis Web服务开发工具有基本的了解； 
</li>
				<li>基本的Java编程知识。 </li>
		</ul>
		<p>如果使用JAX-RPC开发Web服务，我们几种选择：</p>
		<ul>
				<li>Servlet作为Web服务端点； 
</li>
				<li>无状态会话Bean作为Web服务端点； 
</li>
				<li>基于消息（如JMS）的应用程序作为Web服务端点。 </li>
		</ul>
		<p>本文以Servlet作为Web服务端点的情况来介绍JAX-RPC Web服务开发，关于本篇文章中案例的介绍详见本系列文章第一篇： <a href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jaxm/part1/index.html"><font color="#5c81a7">《用JAXM开发Web服务》</font></a>。 </p>
		<p>本文的参考资料见 <a href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#resources"><font color="#996699">参考资料</font></a></p>
		<p>本文的全部代码在这里 <a href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#resources"><font color="#996699">下载</font></a></p>
		<p>
				<a name="0">
						<span class="atitle">
								<font face="Arial" size="4">JAX-RPC快速入门</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>JAX-RPC，Java™ API for XMLbased RPC，顾名思义，它是一种远程方法调用（或者说远程过程调用），那么它和其它的远程方法调用（RPC， COM，CORBA，RMI）有什么区别呢？我们看一般的远程方法调用的结构，如图1所示。</p>
		<br />
		<img height="325" alt="图1 远程方法调用" src="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/1.gif" width="533" />
		<br />
		<p>综合比较常用的远程方法调用技术，它们有以下的共性：</p>
		<ul>
				<li>在客户端和服务端有通用编程接口； 
</li>
				<li>在客户端有Stub，在服务端有Tie（有的叫Skeleton）； 
</li>
				<li>客户端和服务端有专门的协议进行数据传输。 </li>
		</ul>
		<p>对于通用接口的描述，比如CORBA有IDL of CORBA，Java RMI有Java RMI interface in RMI，对于XMLbased RPC来说，IDL就是WSDL（Web服务描述语言）。那么XMLbased RPC来说，什么是这个结构中的"传输协议"，当然是SOAP，SOAP消息通过以传输文本为基础的协议（HTTP、SMTP、FTP）为载体来使用的，也就是说，SOAP消息的传输建立在HTTP、SMTP、FTP传输协议之上。</p>
		<p>JAX-RPC的构架如下。</p>
		<br />
		<img height="321" alt="图2 JAX-RPC 的构架" src="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/2.gif" width="534" />
		<br />
		<p>从上图可以看出，客户端调用的是JAX-RPC服务端点(Service Endpoint)，这个服务端点是通过WSDL语言描述的。在这个体系结构中，对于客户端，可以是JS2E、J2ME或者J2EE平台运行环境；对于服务端，可以是J2EE1.3或者J2EE1.4容器（Servlet容器或者EJB容器）。Apache axis是一个很好的JAX-RPC运行环境实现，同时也提供了优秀的开发工具，本文将使用它进行开发。</p>
		<p>使用Servlet作为服务端点，本案例的基本构架如下图所示。</p>
		<br />
		<img height="310" alt="图3 案例的基本构架" src="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/3.gif" width="504" />
		<br />
		<p>客户端通过SOAP消息和JAX-RPC服务端交互，JAX-RPC服务端运行在Servlet容器中，它通过调用EJB容器中的EJB组件来处理具体的业务逻辑。</p>
		<p>使用JAX-RPC开发Web服务，可以按照以下的步骤进行：</p>
		<ol>
				<li>服务端点定义； 
</li>
				<li>服务描述； 
</li>
				<li>服务端点实现； 
</li>
				<li>服务端点部署； 
</li>
				<li>服务发布和发现。 </li>
		</ol>
		<p>注意：对于服务的发布和发现，由于机制比较复杂，本文不讨论，可能会在本系列文章进行专题讨论。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="1">
						<span class="atitle">
								<font face="Arial" size="4">开发快速入门</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>一个完整的JAX-RPC开发实例，将按照上面的5个步骤进行，但是我们也可以使用非常简单的方式来发布一个Web服务。在介绍我们的案例前，让我们用一分钟快速开发一个Web服务。</p>
		<p>首先安装好JWSDP，你可以从 <a href="http://java.sun.com/webservices"><font color="#5c81a7">http://java.sun.com/webservices</font></a>下载。 </p>
		<p>把本案例源代码中的\src\bookservice.ear\web.war目录拷贝到%JWSDP_HOME%\webapps目录下，web.war文件里已经包括了Apache axis运行环境。</p>
		<p>在%JWSDP_HOME%\classes目录下新建一个HelloWorld.java文件，它的代码如下：</p>
		<p>例程1 最简单的Web服务HelloWorld</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package com.hellking.webservice;
public class HelloWorld
{
 public String sayHello(String name)
 {
  return "Hello! "+name;
 }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>编译这个类，然后编辑%JWSDP_HOME%\webapps\WEB-INF\server-config.wsdd文件，找到&lt;/service&gt;标记，在其后面加入以下内容：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console"> &lt;service name="HelloWorld" provider="java:RPC"&gt;
  &lt;parameter name="allowedMethods" value="sayHello"/&gt;
  &lt;parameter name="className" value="com.hellking.webservice.HelloWorld"/&gt;
 &lt;/service&gt;
 </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在浏览器例输入：</p>
		<a href="http://localhost:8080/web/services/HelloWorld?wsdl">
				<font color="#5c81a7">http://localhost:8080/web/services/HelloWorld?wsdl</font>
		</a>
		<p>如果出现部署WSDL描述文件，那么最简单的Web服务已经部署成功！</p>
		<p>下面我们使用最简单的方式来调用这个Web服务，在浏览器里输入：</p>
		<a href="http://localhost:8080/web/services/HelloWorld?wsdl&amp;method=sayHello&amp;name=hellking">
				<font color="#5c81a7">http://localhost:8080/web/services/HelloWorld?wsdl&amp;method=sayHello&amp;name=hellking</font>
		</a>
		<p>那么在浏览器将会显示以下内容：</p>
		<p>例程2 在浏览器里调用Web服务</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">     &lt;?xml version="1.0" encoding="UTF-8" ?&gt; 
 &lt;soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
 &lt;soapenv:Body&gt;
 &lt;sayHelloResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&gt;
  &lt;sayHelloReturn xsi:type="xsd:string"&gt;Hello! hellking&lt;/sayHelloReturn&gt; 
  &lt;/sayHelloResponse&gt;
  &lt;/soapenv:Body&gt;
  &lt;/soapenv:Envelope&gt;
  </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>如果结果是这样，那么最简单的Web服务已经部署成功，并且测试也通过了。注意"Hello！hellking"是调用Web服务返回的结果，它是我们期望的。下面我们来看一个完整的Web服务开发的例子。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="2">
						<span class="atitle">
								<font face="Arial" size="4">服务端点定义</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>服务端点定义的工作主要是确定"服务定义接口"（Service Definition Interface），有时也叫Web服务端点接口（Web services endpoint interface）。服务端点定义有两中方法获得：</p>
		<ul>
				<li>使用某些工具从WSDL文件获得； 
</li>
				<li>直接使用Java语言编写。 </li>
		</ul>
		<p>Apache axis提供了从WSDL文件中获得Web服务端点的工具。您可以这样使用：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">java org.apache.axis.wsdl.WSDL2Java (WSDL-file-URL)
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>使用这个命令前先设置好以下的环境变量，后面的介绍中还会使用axis工具，它们也要这样设置环境变量：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">SET AXIS_HOME=&lt;axis安装目录&gt;
set CLASSPATH=%CLASSPATH%;
%AXIS_HOME%/axis-1_1/lib/axis.jar; 
%AXIS_HOME%/axis-1_1/lib/jaxrpc.jar; 
%AXIS_HOME%/axis-1_1/lib/saaj.jar;
%AXIS_HOME%/axis-1_1/lib/commons-logging.jar;
%AXIS_HOME%/axis-1_1/lib/commons-discovery.jar;
%AXIS_HOME%/axis-1_1/lib/wsdl4j.jar;.
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>关于WSDL2Java的更详细的使用，请参考Apache axis的User Guides（ <a href="http://ws.apache.org/axis/"><font color="#5c81a7">http://ws.apache.org/axis/</font></a>）。 </p>
		<p>我们这里直接使用Java编写服务端点接口的方法。在本案例中，定义了三个业务方法，它们分别是查找所有的图书、按书名查找图书、按类别查找图书。那么安照这三个业务方法，可以定义出以下的服务端点接口：</p>
		<p>例程3 服务端点定义（BookServiceInterface.java）</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package com.hellking.webservice.servlet;
/**
  *@author hellking
  */
import java.util.Collection;
import com.hellking.webservice.BookVO;
public interface BookServiceInterface
{
   
   /**
    * @return Vector
    */
   public Collection getAllBooks();//查找所有的图书
   
   /**
    * @param name
    * @return BookVO
    */
   public BookVO getTheBookDetail(String name);//按照书名查找图书
   
   /**
    * @return Collection
    */
   public Collection getBookByCategory(String category);//按类别查找
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>上面代码中的BookVO是一个序列化的对象，它有以下属性，每个属性都提供了getter和setter方法。</p>
		<p>例程4 BookVO的部分代码</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">public class BookVO implements java.io.Serializable
{
   private String name;
   private String publisher;
   private float price;
   private String isbn;
   private String description;
   private String category;
   private Collection authors;   
     
   public void setName(String name)
   {
     this.name=name;
   }
public String getName()
    {
     return this.name;
    }
…
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>编译好这两个类。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="3">
						<span class="atitle">
								<font face="Arial" size="4">服务端点描述</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>可以使用Java2WSDL从以上定义的服务端点接口中获得服务描述（WSDL文件）。使用Apache axis工具，只要使用以下命令即可：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console"> java org.apache.axis.wsdl.Java2WSDL -o temp.wsdl 
-l"http://localhost:8080/axis/services/BookServletService"
 -n "urn:BookServletService"
 -p"com.hellking.webservice" "urn:BookServletService"
 com.hellking.webservice.servlet.BookServiceInterface
 </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>以上命令的解释：</p>
		<pre>-o：生成的WSDL文件；
-l：Web服务的位置；
-n：这个WSDL文件的名字空间；
-p：包到名字空间的映射；
</pre>
		<p>最后一个参数是Web服务端点接口。</p>
		<p>使用以上命令后，将生成一个名为temp.wsdl Web服务描述文。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="4">
						<span class="atitle">
								<font face="Arial" size="4">服务端点实现</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>有了服务描述文件，就可以使用它来生成JAX-RPC 的框架，这个框架使得我们编程变得简单，当然您也可以直接编写实现代码，然后部署，但是那样编程会变得困难。</p>
		<p>使用以下的命令就可以生成这个框架：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">java org.apache.axis.wsdl.WSDL2Java -o . -d Session -s -S true 
-Nurn:BookServletService com.hellking.webservice.servlet temp.wsdl
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>使用这个命令后将生成以下文件：</p>
		<p>BookServiceInterface.java：新的BookServiceInterface接口，它扩展了java.rmi.Remote接口；</p>
		<p>BookServiceInterfaceService.java：客户端服务接口，用来获得BookServiceInterface对象的引用；</p>
		<p>BookServiceInterfaceServiceLocator.java：在客户端使用，主要用来服务定位；</p>
		<p>BookServletServiceSoapBindingImpl.java：服务端实现类，它实现了BookServiceInterface接口，服务端的业务方法实现代码就在这里编写；</p>
		<p>BookServletServiceSoapBindingSkeleton.java：服务端Skeleton；</p>
		<p>BookServletServiceSoapBindingStub.java：客户端Stub；</p>
		<p>BookVO.java：新的BookVO序列化对象；</p>
		<p>deploy.wsdd：部署这个Web服务的脚本；</p>
		<p>undeploy.wsdd：卸载这个Web服务的脚本。</p>
		<p>服务端点实现类的基本框架已经生成出来了，我们的任务就是往里面增加具体的业务内容。下面我们来看具体的服务端点的实现。如例程3所示。</p>
		<p>例程5 服务端点实现类</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package com.hellking.webservice.servlet;
import java.util.*;
import javax.naming.*;
import com.hellking.webservice.ejb.*;

public class BookServletServiceSoapBindingImpl
 implements com.hellking.webservice.servlet.BookServiceInterface{
   InitialContext init=null;
 BookServiceFacadeHome facadeHome;
 
    public BookServletServiceSoapBindingImpl()
    {
     try
     {
      init=new InitialContext();
     }
     catch(Exception e)
     {
     }
    } 
       
   //业务方法，查找所有的图书
 public java.lang.Object[] getAllBooks() throws java.rmi.RemoteException {
             System.out.println("getAllBooks");

        try
        {
         Object objref = init.lookup("ejb/bookfacade");  
         facadeHome = (BookServiceFacadeHome)javax.rmi.PortableRemoteObject.narrow(
objref, BookServiceFacadeHome.class); 
      Collection result=facadeHome.create().getAllBook(); 
      System.out.println(result.size());
              Object[] ret=new Object[result.size()];
       Iterator it=result.iterator();
      int i=0;
      while(it.hasNext())
      {
       ret[i++]=it.next();
      } 
  // System.out.println(((BookVO)ret[0]).getName());
        return ret;   
  }
  catch(Exception e)
  {
   e.printStackTrace();
   return null;
  }  
    }
    //业务方法，按书名查找图书
    public com.hellking.webservice.BookVO getTheBookDetail(java.lang.String in0)
 throws java.rmi.RemoteException {
         com.hellking.webservice.BookVO ret=null;
        try
        {
         Object objref = init.lookup("ejb/bookfacade");  
         facadeHome = (BookServiceFacadeHome)javax.rmi.PortableRemoteObject.narrow(
objref, BookServiceFacadeHome.class); 
      Collection result=facadeHome.create().getBookDetail(in0);
      Iterator it=result.iterator();
      while(it.hasNext())
      {
       ret=( com.hellking.webservice.BookVO)it.next();
      } 

   }   
  catch(Exception e)
  {
  }  
  return ret;
    }
//业务方法，按类别查找图书
    public java.lang.Object[] getBookByCategory(java.lang.String in0)
 throws java.rmi.RemoteException {
         try
        {
         Object objref = init.lookup("ejb/bookfacade");  
         facadeHome = (BookServiceFacadeHome)javax.rmi.PortableRemoteObject.narrow(
objref, BookServiceFacadeHome.class); 
      System.out.println(in0);
      Collection result=facadeHome.create().findByCategory(in0); 
      Object[] ret=new Object[result.size()];
      Iterator it=result.iterator();
      int i=0;
      while(it.hasNext())
      {
       ret[i++]=it.next();
       System.out.println(i);
      } 
   return ret;   
  }
  catch(Exception e)
  {
   e.printStackTrace();
   return null;
  }  
 }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>可以看出，服务端点的主要任务是调用EJB组件来完成业务逻辑的。</p>
		<p>需要向读者说明的是，为了和本系列第一篇文章中的客户端框架兼容（客户端使用的值对象是com.hellking.webservice.BookVO，而这里由WSDL2Java生成的值对象是com.hellking.webservice.servlet.BookVO）。我们需要做以下的改动：</p>
		<p>把生成的这些代码中的com.hellking.webservice.servlet.BookVO全部改为com.hellking.webservice.BookVO，然后在Apache axis服务配置文件中申明这个BeanMapping，具体的声明方法在后面介绍。</p>
		<p>接下来的工作是编译服务端相关的文件：BookServletServiceSoapBindingImpl、BookServletServiceSoapBindingSkeleton、BookServiceInterfaceService、BookServiceInterface。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="5">
						<span class="atitle">
								<font face="Arial" size="4">服务端点部署</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>启动服务器，这个服务器可以是任何能够运行Apache引擎Web服务器，当然最好是同时有EJB容器和EJB容器的服务器，如Webphere 、Weblogic、JBOSS，如果没有EJB容器，还需要一个额外的EJB容器，并且需要更改BookServletServiceSoapBindingImpl中获得上下文（InitialContext）的方法，如：</p>
		<p>例程6 获得上下文环境</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">     Properties p = new Properties();   
     p.put(Context.INITIAL_CONTEXT_FACTORY, "xxxxx");
     p.put(Context.URL_PKG_PREFIXES, "xxxx");
     p.put(Context.PROVIDER_URL, "xxxx");
     init=new javax.naming.InitialContext(p);
     </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在控制台中，转到deploy.wsdd目录下，执行以下的命令就可以完成部署：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console"> java org.apache.axis.client.AdminClient deploy.wsdd
 </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>由于我们使用的是自己的序列化Bean对象，故要在%Web-Apps%/WEB-INF/ server-config.wsdd文件中做以下更改： <br />找到 </p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">&lt;service name="BookServletService" provider="java:RPC"&gt;
…
&lt;/service&gt;
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在中间加入以下内容：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console"> &lt;beanMapping languageSpecificType="java:com.hellking.webservice.BookVO"
 qname="ns7:BookServletService" xmlns:ns7="BookServletService"/&gt;
 </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>部署后您必须确保在%Web-Apps%/WEB-INF/classes目录下有服务端相关的类（BookServletServiceSoapBindingImpl、BookServletServiceSoapBindingSkeleton等）。</p>
		<p>在浏览器里输入（这个地址您需要根据具体情况更改）：</p>
		<p>
				<a href="http://localhost:8080/axis/services/BookServletService?wsdl">
						<font color="#5c81a7">http://localhost:8080/axis/services/BookServletService?wsdl</font>
				</a>
		</p>
		<p>来验证Web服务是否已经部署成功，如果部署不成功，您可以先尝试重新启动服务器。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="6">
						<span class="atitle">
								<font face="Arial" size="4">客户端</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>如果服务端已经成功部署，下一步的工作就是编写客户端程序了。由于使用WSDL2Java已经生成了客户端的框架，所以我们的任务将相对简单了。</p>
		<p>客户端编程任务主要有以下几个：</p>
		<ul>
				<li>在BookServletServiceSoapBindingStub里注册BeanMapping； 
</li>
				<li>编写客户端业务代表，这里使用了JAXRPCDelegate； 
</li>
				<li>更改以前的BookGUI的部分程序。 </li>
		</ul>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="7">
						<span class="atitle">
								<font face="Arial" size="4">在BookServletServiceSoapBindingStub里注册BeanMapping</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>由于在SOAP消息中使用了序列化的BookVO对象，故在BookServletServiceSoapBindingStub中要进行BeanMapping注册。具体方法：</p>
		<p>找到BookServletServiceSoapBindingStub中的getAllBooks，getTheBookDetail，getBookByCategory方法，在每个方法中的</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console"> java.lang.Object _resp = _call.invoke(new java.lang.Object[] {in0});
 </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>前加入以下代码：</p>
		<p>例程7 在BookServletServiceSoapBindingStub注册BeanMapping</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console"> QName    qn      = new QName( "BookServletService", "BookServletService" );
 _call.registerTypeMapping(com.hellking.webservice.BookVO.class, qn,                
new org.apache.axis.encoding.ser.BeanSerializerFactory(com.hellking.webservice.BookVO.class, qn),        
 new org.apache.axis.encoding.ser.BeanDeserializerFactory(com.hellking.webservice.BookVO.class, qn));
 </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>注意这里的Qname要和server-config.wsdd中描述的名称空间一致。在中server-config.wsdd，我们使用了以下的映射：</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console"> &lt;beanMapping languageSpecificType="java:com.hellking.webservice.BookVO"
 qname="ns7:BookServletService" xmlns:ns7="BookServletService"/&gt;
 </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在编写业务代表程序前，我们先来对Web服务做一个调用测试。在测试前您必须保证数据库里已经有图书信息。如果EJB和Web Application都部署好，您可以通过以下页面来往数据库里增加数据：</p>
		<p>
				<a href="http://localhost:8080/axis/insert_data.jsp">
						<font color="#5c81a7">http://localhost:8080/axis/insert_data.jsp</font>
				</a>
		</p>
		<p>测试代码如下：</p>
		<p>例程8 测试Web服务</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package com.hellking.webservice.servlet;
import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import com.hellking.webservice.ejb.*;

public class Client { 
    public static void main(String[] args) {      
        try {
            
            BookServiceInterfaceServiceLocator locator=new BookServiceInterfaceServiceLocator();
            
        
        <span class="boldcode"><strong>BookServiceInterface myProxy=locator.getBookServletService();</strong></span>
            Object[] c=myProxy.getAllBooks();
            com.hellking.webservice.BookVO 
book=(com.hellking.webservice.BookVO)c[0];
            System.out.println(book.getName());            
        } catch (Exception ex) {
            ex.printStackTrace();
        } 
    } 
}

      
      </font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>如果在控制台里打印出某个图书的名字，那么就验证了客户端和服务端的部署是正确的。在进行下面的工作前，请确保这个测试是成功的。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="8">
						<span class="atitle">
								<font face="Arial" size="4">编写客户端业务代表</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>对于客户端程序来说，业务代表直接和Web服务打交道，获得Web服务返回的数据，并做对应的处理，然后把数据返回给GUI程序，GUI程序只负责数据显示。业务代表的代码如下：</p>
		<p>例程9 JAXRPCDelegate业务代表</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package com.hellking.webservice.servlet;

import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import com.hellking.webservice.ejb.*;
import java.util.*;

public class JAXRPCDelegate implements com.hellking.webservice.BookBusiness
{
  BookServiceInterfaceServiceLocator locator;
     com.hellking.webservice.servlet.BookServiceInterface bookService;
     
     public JAXRPCDelegate()
  {
   try
   {
    locator=new BookServiceInterfaceServiceLocator();
          bookService=locator.getBookServletService();
         }
         catch(Exception e)
         {
         }
    }
  
 public Collection getBookByCategory(String category)
 {
     System.out.println("by_category");
  Collection ret=new ArrayList();
  try
  {   
            Object[] books=bookService.getBookByCategory(category);
            System.out.println(category);
            int i=0;
            
            while(true)
            {
             ret.add(books[i++]);
             System.out.println(i);
            }   
  }
  catch(Exception e)
  {
  }
  return ret; 
 }
 
 public Collection getAllBooks()
 {
  Collection ret=new ArrayList();
  try
  {   

            Object[] books=bookService.getAllBooks();
            int i=0;
            
            while(true)
            {
             ret.add(books[i++]);
            } 
  }
  catch(Exception e)
  {
  }
  return ret;
 }
 
 public com.hellking.webservice.BookVO getTheBookDetail(String name)
 {
  System.out.println("bookdetail");
  com.hellking.webservice.BookVO ret=new com.hellking.webservice.BookVO();
  try
  {   
           ret=bookService.getTheBookDetail(name);
  }
  catch(Exception e)
  {
  }
  return ret;  
 } 
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>和第一篇文章介绍的JAXMDelegate一样，JAXRPCDelegate 同样实现了BookBusiness接口，BookBusiness接口是以前设计的接口，我们在这里进行重用，这样的好处是BookClientGUI程序几只要做很少的更改就可以运行。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="9">
						<span class="atitle">
								<font face="Arial" size="4">更改以前的BookClientGUI的部分程序</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>在BookGUI构造方法里增加以下内容：</p>
		<p>例程10 更改BookGUI程序</p>
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">public BookClientGUI()
{
 business=new JAXRPCDelegate();
…
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>好了，经过以上的奋战，让我们来看运行的结果吧。</p>
		<p>java com.hellking.webservice.BookClientGUI</p>
		<p>运行结果如图4所示。</p>
		<br />
		<img height="294" alt="图4 运行结果." src="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/4.gif" width="543" />
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="10">
						<span class="atitle">
								<font face="Arial" size="4">总结</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>通过以上的介绍，相信读者对JAX-RPC Web服务开发已经有一个比较深刻的认识。总结一下，使用JAX-RPC开发Web服务时，主要有以下的工作：</p>
		<ul>
				<li>服务端点定义； 
</li>
				<li>服务描述； 
</li>
				<li>服务端点实现； 
</li>
				<li>服务端点部署； </li>
		</ul>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="11">
						<span class="atitle">
								<font face="Arial" size="4">下一步</font>
						</span>
				</a>
		</p>
		<p>
				<font face="Arial" size="4">
				</font>
		</p>
		<p>本文已经介绍了把Servlet作为Web服务端点开发Web服务的全过程，下一篇将是把EJB作为Web服务端点来开发。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="resources">
						<span class="atitle">
								<font face="Arial" size="4">参考资料 </font>
						</span>
				</a>
		</p>
		<p>Apache axis User's Guides： <a href="http://ws.apache.org/axis/"><font color="#5c81a7">http://ws.apache.org/axis/</font></a><br />Sun jwsdp-1_1-tutorial， <a href="http://java.sun.com/webservices/downloads/webservicestutorial.html"><font color="#5c81a7">http://java.sun.com/webservices/downloads/webservicestutorial.html</font></a><br /><a href="http://www-128.ibm.com/developerworks/cn/xml/index.html"><font color="#5c81a7">http://www.ibm.com/developerworks/cn/xml/index.shtml</font></a>XML &amp; Web services专区 <br />JAX-RPC API <a href="http://java.sun.com/webservices"><font color="#5c81a7">http://java.sun.com/webservices</font></a><br />Jwdp1.1 <a href="http://java.sun.com/webservices"><font color="#5c81a7">http://java.sun.com/webservices</font></a><br />下载 <a href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/src.zip"><font color="#5c81a7">样例代码</font></a></p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="author">
						<span class="atitle">
								<font face="Arial" size="4">关于作者</font>
						</span>
				</a>
		</p>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td colspan="3">
										<font face="Arial" size="4">
												<img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										</font>
								</td>
						</tr>
						<tr valign="top" align="left">
								<td>
										<p>
												<font face="Arial" size="4">
												</font>
										</p>
								</td>
								<td>
										<font face="Arial" size="4">
												<img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" />
										</font>
								</td>
								<td width="100%">
										<p>陈亚强：北京华园天一科技有限公司高级软件工程师，擅长J2EE技术，曾参与多个J2EE项目的设计和开发，对Web服务有很大的兴趣并且有一定的项目经验。热爱学习，喜欢新技术。即将由电子工业出版社出版的《J2EE企业应用开发》正在最终定稿阶段，目前正从事J2EE方面的开发和J2EE Web服务方面的图书写作。您可以通过 <a href="mailto:cyqcims@mail.tsinghua.edu.cn"><font color="#5c81a7">cyqcims@mail.tsinghua.edu.cn</font></a>和他联系。 </p>
								</td>
						</tr>
				</tbody>
		</table>
		<br />引用地址：<a href="http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html">http://www-128.ibm.com/developerworks/cn/webservices/ws-jax-rpc/part1/index.html</a><img src ="http://www.cnitblog.com/xiaoyaocao/aggbug/17455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/xiaoyaocao/" target="_blank">逍遥草</a> 2006-09-28 18:43 <a href="http://www.cnitblog.com/xiaoyaocao/archive/2006/09/28/17455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>测试J2EE Web Services</title><link>http://www.cnitblog.com/xiaoyaocao/archive/2006/09/18/16996.html</link><dc:creator>逍遥草</dc:creator><author>逍遥草</author><pubDate>Mon, 18 Sep 2006 07:51:00 GMT</pubDate><guid>http://www.cnitblog.com/xiaoyaocao/archive/2006/09/18/16996.html</guid><wfw:comment>http://www.cnitblog.com/xiaoyaocao/comments/16996.html</wfw:comment><comments>http://www.cnitblog.com/xiaoyaocao/archive/2006/09/18/16996.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/xiaoyaocao/comments/commentRss/16996.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/xiaoyaocao/services/trackbacks/16996.html</trackback:ping><description><![CDATA[
		<!-- 提取技术文章 --> 
<div class="beas"><span style="COLOR: black; FONT-FAMILY: 宋体">我们已经了解了很多关于</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">开发方面的知识，而对于</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">测试所面临的挑战却知之甚少。本文将阐述对</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">功能性和互用性的测试。本文同时也指出了与传统测试模式相比</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">测试所面临的挑战。本文的目标读者是开发人员、测试人员以及那些对</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的技术知识或工作方式没有深入了解的项目经理。同时本文假设读者已经很熟悉</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的基本知识。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></div><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: Verdana"><a href="http://ftpna2.bea.com/pub/downloads/J2EE_PatilParam.zip"><span style="COLOR: #00235d; FONT-FAMILY: 宋体">下载</span></a></span><span style="COLOR: black; FONT-FAMILY: 宋体">作者提供的与本文相关的文件</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">以下所述及的示例的环境由</span><span style="COLOR: black; FONT-FAMILY: Verdana">WebLogic Server 8.1</span><span style="COLOR: black; FONT-FAMILY: 宋体">和</span><span style="COLOR: black; FONT-FAMILY: Verdana">Microsoft Windows .Net</span><span style="COLOR: black; FONT-FAMILY: 宋体">构成，二者所用操作系统均为</span><span style="COLOR: black; FONT-FAMILY: Verdana">Windows 2000</span><span style="COLOR: black; FONT-FAMILY: 宋体">。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><h3><span style="FONT-FAMILY: 宋体">挑战</span><span></span></h3><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">测试</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的有效性、性能、可伸缩性、可靠性以及安全性时所面临的主要挑战是</span><span style="COLOR: black; FONT-FAMILY: Verdana"> Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的分布性。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">为了使完整的</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">能够实现预期的功能，就要求客户端和服务都要满足一系列的要求。接口必须在其</span><span style="COLOR: black; FONT-FAMILY: Verdana">WSDL</span><span style="COLOR: black; FONT-FAMILY: 宋体">文档中正确描述出来，消息必须遵守传输协议规范（如</span><span style="COLOR: black; FONT-FAMILY: Verdana">HTTP1.1</span><span style="COLOR: black; FONT-FAMILY: 宋体">）和消息协议（如</span><span style="COLOR: black; FONT-FAMILY: Verdana">SOAP 1.1</span><span style="COLOR: black; FONT-FAMILY: 宋体">）。同时消息必须遵守描述该服务的</span><span style="COLOR: black; FONT-FAMILY: Verdana">WSDL</span><span style="COLOR: black; FONT-FAMILY: 宋体">文档中的契约，要求同时考虑到消息的内容和传输层的绑定。加上综合的安全条款、互操作性问题、</span><span style="COLOR: black; FONT-FAMILY: Verdana">UDDI</span><span style="COLOR: black; FONT-FAMILY: 宋体">注册要求以及一定负载下的性能需求，就很容易发现为什么网络测试不是无足轻重的事情。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">组件可由多个利益相关者来共同构建和部署。因此，测试这些组件过程中会发现确定代码质量、可用性等都有很大的难度。</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的标准是简单的，数据驱动的，并且共享一个公共的基于</span><span style="COLOR: black; FONT-FAMILY: Verdana">XML</span><span style="COLOR: black; FONT-FAMILY: 宋体">的基础。传统的测试工具可能不足以有效地测试这些标准。而且</span><span style="COLOR: black; FONT-FAMILY: Verdana">GUI</span><span style="COLOR: black; FONT-FAMILY: 宋体">自动化工具也不足以有效地测试</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的接口点和消息格式。</span><span style="FONT-SIZE: 7pt; COLOR: black; FONT-FAMILY: Verdana"></span></p><h3><span style="FONT-FAMILY: 宋体">功能测试</span><span></span></h3><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">该测试的目标相当直观易懂：确保服务器能够对给定的请求发送正确的响应。然而，由于</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的复杂性，该任务原非想象的那么简单。对于大多数的</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">而言，它不可能精确预见客户端会发来什么类型的请求。枚举所有可能的请求并不切实可行，因为可能输入的空间要么是没有边界，要么就是无穷大。因此，验证服务器是否能处理大范围的请求类型和参数是极其重要的。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="Normal" valign="top" bgcolor="#cccccc"><p style="TEXT-ALIGN: left" align="left"><span>  </span>public boolean execute(String action, String symbol, int quantity) </p><p style="TEXT-ALIGN: left" align="left"><span>  </span>throws javax.xml.soap.SOAPException{</p><p style="TEXT-ALIGN: left" align="left"><span>     </span>Detail detail = null;</p><p style="TEXT-ALIGN: left" align="left"><span>     </span>detail = SOAPFactory.newInstance().createDetail();</p><p style="TEXT-ALIGN: left" align="left"><span>     </span>detail.addChildElement( "Stock Trade" ).addTextNode( "failed" );</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>System.out.println("execute() in webservices.stock.trade webservice has been invoked </p><p style="TEXT-ALIGN: left" align="left"><span>      </span>with following arguments:: action:" + action +</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>" symbol:" + symbol + " quantity:" + quantity);</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>if(action == null) {</p><p style="TEXT-ALIGN: left" align="left"><span>        </span>throw new SOAPFaultException(new QName( "http://StockTrade/execute", "ServerFailed" ),</p><p style="TEXT-ALIGN: left" align="left"><span>                                                </span>"action parameter is null.",</p><p style="TEXT-ALIGN: left" align="left"><span>                                                </span>null,</p><p style="TEXT-ALIGN: left" align="left"><span>                         </span>                       detail);</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>}</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>if(symbol == null) {</p><p style="TEXT-ALIGN: left" align="left"><span>        </span>throw new SOAPFaultException(new QName( "http://StockTrade/execute", "ServerFailed" ),</p><p style="TEXT-ALIGN: left" align="left"><span>                                                </span>"symbol parameter is null.",</p><p style="TEXT-ALIGN: left" align="left"><span>                 </span>                               null,</p><p style="TEXT-ALIGN: left" align="left"><span>                                                </span>detail);</p><p style="TEXT-ALIGN: left" align="left"><span>   </span>}</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>if(action.equalsIgnoreCase("BUY"))</p><p style="TEXT-ALIGN: left" align="left"><span>        </span>System.out.println("BUYING quantity: "+ quantity + " of symbol:" + symbol);</p><p style="TEXT-ALIGN: left" align="left"><span>        </span>// Invoke method to execute trade here.</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>else if(action.equalsIgnoreCase("SELL"))</p><p style="TEXT-ALIGN: left" align="left"><span>        </span>System.out.println("SELLING quantity: "+ quantity + " of symbol:" + symbol);</p><p style="TEXT-ALIGN: left" align="left"><span>        </span>// Invoke method to execute trade here.</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>else</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>{</p><p style="TEXT-ALIGN: left" align="left"><span>        </span>System.out.println("INVALID action: "+ action);</p><p style="TEXT-ALIGN: left" align="left"><span>        </span>throw new SOAPFaultException(new QName( "http://StockTrade/execute", "ServerFailed" ),</p><p style="TEXT-ALIGN: left" align="left"><span>                                                </span>"Invalid Action:" + action,</p><p style="TEXT-ALIGN: left" align="left"><span>                                                </span>null,</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>                                detail);</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>}</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>return true;</p><p style="TEXT-ALIGN: left" align="left"><span>    </span>}</p></td></tr></tbody></table><h3><span style="FONT-FAMILY: 宋体">代码摘录</span><span style="FONT-FAMILY: 宋体">：</span><span>Stock Trade Web Services</span></h3><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">该段摘录的代码是</span><span style="COLOR: black; FONT-FAMILY: Verdana">Stock Trade Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的</span><span style="COLOR: black; FONT-FAMILY: Verdana">“execute()”</span><span style="COLOR: black; FONT-FAMILY: 宋体">方法的实现代码。该方法首先验证输入参数的有效性，验证成功才执行功能。举例说明，如果参数</span><span style="COLOR: black; FONT-FAMILY: Verdana">action</span><span style="COLOR: black; FONT-FAMILY: 宋体">是空值，它就会抛出一个</span><span style="COLOR: black; FONT-FAMILY: Verdana">SoapFaultException</span><span style="COLOR: black; FONT-FAMILY: 宋体">异常，用</span><span style="COLOR: black; FONT-FAMILY: Verdana">faultstring</span><span style="COLOR: black; FONT-FAMILY: 宋体">参数（第二个参数）说明造成异常的原因。为了举例说明，在对参数</span><span style="COLOR: black; FONT-FAMILY: Verdana">symbol</span><span style="COLOR: black; FONT-FAMILY: 宋体">进行相似的验证之后，</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">给出了处理机。在实际的情况下，商业逻辑应该在此位置中实现：</span><span style="FONT-SIZE: 7pt; COLOR: black; FONT-FAMILY: Verdana"></span></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="Normal" valign="top" bgcolor="#cccccc"><p style="TEXT-ALIGN: left" align="left"><span>  </span>try{</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>// Setup the global JAXM message factory</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>System.setProperty("javax.xml.soap.MessageFactory",</p><p style="TEXT-ALIGN: left" align="left"><span>         </span>"weblogic.webservice.core.soap.MessageFactoryImpl");</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>// Setup the global JAX-RPC service factory</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>System.setProperty( "javax.xml.rpc.ServiceFactory",</p><p style="TEXT-ALIGN: left" align="left"><span>         </span>"weblogic.webservice.core.rpc.ServiceFactoryImpl");</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>StockTrade_Impl ws = new StockTrade_Impl();</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>StockTradePort port  = ws.getStockTradePort();</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>boolean returnVal = port.execute(action, symbol, quantity);</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>System.out.println("The webservice got back the following result:" + returnVal);</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>}catch(Exception e) {</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>}</p></td></tr></tbody></table><h3><span style="FONT-FAMILY: 宋体">代码摘录</span><span style="FONT-FAMILY: 宋体">：</span><span>Web Services</span><span style="FONT-FAMILY: 宋体">的客户端</span><span></span></h3><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">上面的一段代码描述了测试客户端如何激活前面讨论的</span><span style="COLOR: black; FONT-FAMILY: Verdana">Stock Trade Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">，</span><span style="COLOR: black; FONT-FAMILY: 宋体">该例子使用了</span><span style="COLOR: black; FONT-FAMILY: Verdana">JAX-RPC API</span><span style="COLOR: black; FONT-FAMILY: 宋体">（</span><span style="COLOR: black; FONT-FAMILY: Verdana">JAX</span><span style="COLOR: black; FONT-FAMILY: 宋体">远程处理应用程序接口函数</span><span style="COLOR: black; FONT-FAMILY: 宋体">），</span><span style="COLOR: black; FONT-FAMILY: 宋体">并且假设在读者的</span><span>CLASSPATH</span><span style="COLOR: black; FONT-FAMILY: 宋体">中已经含有了必要的</span><span style="COLOR: black; FONT-FAMILY: Verdana">BEA</span><span style="COLOR: black; FONT-FAMILY: 宋体">提供的</span><span style="COLOR: black; FONT-FAMILY: Verdana">JAR</span><span style="COLOR: black; FONT-FAMILY: 宋体">文件。这是一个静态实现，在这里可获得一个</span><span style="COLOR: black; FONT-FAMILY: Verdana">stub</span><span style="COLOR: black; FONT-FAMILY: 宋体">实现的实例。获得</span><span style="COLOR: black; FONT-FAMILY: Verdana">stub</span><span style="COLOR: black; FONT-FAMILY: 宋体">实现后，</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的“</span><span style="COLOR: black; FONT-FAMILY: Verdana">execute</span><span style="COLOR: black; FONT-FAMILY: 宋体">”方法就会被激活。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><h3><span style="FONT-FAMILY: 宋体">互操作性测试</span><span></span></h3><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: Verdana">SOAP</span><span style="COLOR: black; FONT-FAMILY: 宋体">和</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的承诺之一就是互操作性。就是两个应用系统可以自动交互而不需要人为的介入。</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">未来成功的关键就在于互操作性。</span><span style="COLOR: black; FONT-FAMILY: Verdana"><br /><br /></span></p><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">互操作性测试套件的目标应针对于测试以下方面：</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">服务器分析客户端的</span><span style="COLOR: black; FONT-FAMILY: Verdana">SOAP</span><span style="COLOR: black; FONT-FAMILY: 宋体">包的能力。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">服务器对包中所含的已编码参数进行反串行化的能力。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">客户端对由服务器作为响应发送而来的</span><span style="COLOR: black; FONT-FAMILY: Verdana">SOAP</span><span style="COLOR: black; FONT-FAMILY: 宋体">包进行分析的能力。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">客户端对从服务器发回的已编码参数进行反串行化的能力。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><h3><span style="FONT-FAMILY: 宋体">测试模式</span><span></span></h3><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">对于一个</span><span style="COLOR: black; FONT-FAMILY: Verdana">WLS</span><span style="COLOR: black; FONT-FAMILY: 宋体">客户和</span><span style="COLOR: black; FONT-FAMILY: Verdana">.NET Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">：</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">用</span><span style="COLOR: black; FONT-FAMILY: Verdana">Microsoft Visual Studio</span><span style="COLOR: black; FONT-FAMILY: 宋体">在目录</span><span style="COLOR: black; FONT-FAMILY: Verdana">/InetPub/wwwroot/DotNetServices/</span><span style="COLOR: black; FONT-FAMILY: 宋体">下创建一个</span><span style="COLOR: black; FONT-FAMILY: Verdana">.NET Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">在</span><span style="COLOR: black; FONT-FAMILY: Verdana">WLS</span><span style="COLOR: black; FONT-FAMILY: 宋体">端，在为</span><span style="COLOR: black; FONT-FAMILY: Verdana">DotNetService </span><span style="COLOR: black; FONT-FAMILY: 宋体">提供了</span><span style="COLOR: black; FONT-FAMILY: Verdana">WSDL URL</span><span style="COLOR: black; FONT-FAMILY: 宋体">后，用</span><span style="COLOR: black; FONT-FAMILY: Verdana">WebLlogic clientgen ant task</span><span style="COLOR: black; FONT-FAMILY: 宋体">生成一个</span><span style="COLOR: black; FONT-FAMILY: Verdana">clientjar</span><span style="COLOR: black; FONT-FAMILY: 宋体">。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">从</span><span style="COLOR: black; FONT-FAMILY: Verdana">testclient</span><span style="COLOR: black; FONT-FAMILY: 宋体">，对</span><span style="COLOR: black; FONT-FAMILY: Verdana">JAVA Stub</span><span style="COLOR: black; FONT-FAMILY: 宋体">进行一次调用。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="Normal" valign="top" bgcolor="#cccccc"><p style="TEXT-ALIGN: left" align="left"><span>  </span>WebLogic Server</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>.NET Server</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>.NET Web Service</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>WLS Client</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>       // STOCK TRADE WEB SERVICE</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>       // The Stock Trade web service executes a trade and returns result.</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>   [WebMethod]</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>    public bool execute(string action, string symbol, int quantity)</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>   {</p><p style="TEXT-ALIGN: left" align="left"><span>      </span>                     if(action == null) {</p><p style="TEXT-ALIGN: left" align="left"><span>       </span>                      Console.WriteLine("action null");</p><p style="TEXT-ALIGN: left" align="left"><span>                        </span>return false;</p><p style="TEXT-ALIGN: left" align="left"><span>                                         </span>}</p><p style="TEXT-ALIGN: left" align="left"><span>                   </span>if(symbol == null) {</p><p style="TEXT-ALIGN: left" align="left"><span>                 </span>          Console.WriteLine("symbol null");</p><p style="TEXT-ALIGN: left" align="left"><span>                          </span>return false;</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>                                       }</p><p style="TEXT-ALIGN: left" align="left"><span>                 </span>   if(action.Equals("BUY"))</p><p style="TEXT-ALIGN: left" align="left"><span>              </span>              Console.WriteLine("BUYING quantity: "+ quantity + " of symbol:" + symbol);</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>    else if(action.Equals("SELL"))</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>    Console.WriteLine("SELLING quantity: "+ quantity + " of symbol:" + symbol);</p><p style="TEXT-ALIGN: left" align="left"><span>                     </span>        else {</p><p style="TEXT-ALIGN: left" align="left"><span>                 </span>   Console.WriteLine("INVALID action: "+ action);</p><p style="TEXT-ALIGN: left" align="left"><span>                  </span>  return false;</p><p style="TEXT-ALIGN: left" align="left"><span>                                         </span>}               </p><p style="TEXT-ALIGN: left" align="left"><span>  </span>                           return true;</p><p style="TEXT-ALIGN: left" align="left"><span>                                </span>}</p></td></tr></tbody></table><h3><span style="FONT-FAMILY: 宋体">代码摘录</span><span style="FONT-FAMILY: 宋体">：</span><span>.NET Web Services</span></h3><p class="MsoBodyText2"><span style="FONT-FAMILY: 宋体">上面摘录的一段代码是</span><span>Stock Trade Web Services</span><span style="FONT-FAMILY: 宋体">，</span><span style="FONT-FAMILY: 宋体">它是前面所设计的</span><span>WLS Web Services</span><span style="FONT-FAMILY: 宋体">的</span><span>.NET</span><span style="FONT-FAMILY: 宋体">版。它用与</span><span>JAVA</span><span style="FONT-FAMILY: 宋体">非常相似的</span><span>C#</span><span style="FONT-FAMILY: 宋体">语言编写。文件名是</span><span>“StockTrade.asmx.cs”</span><span style="FONT-FAMILY: 宋体">。</span></p><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">代码编写完成后，在</span><span style="COLOR: black; FONT-FAMILY: Verdana">WebLogic</span><span style="COLOR: black; FONT-FAMILY: 宋体">服务器上部署</span><span style="COLOR: black; FONT-FAMILY: Verdana">WLS</span><span style="COLOR: black; FONT-FAMILY: 宋体">客户程序，在</span><span style="COLOR: black; FONT-FAMILY: Verdana">.NET</span><span style="COLOR: black; FONT-FAMILY: 宋体">框架上部署</span><span style="COLOR: black; FONT-FAMILY: Verdana">.NET Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">，验证客户端是否能调用</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><h3><span>.NET</span><span style="FONT-FAMILY: 宋体">客户端和</span><span>WLS Web </span><span style="FONT-FAMILY: 宋体">服务器端</span><span></span></h3><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">创建一个</span><span style="COLOR: black; FONT-FAMILY: Verdana">WLS Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">（</span><span style="COLOR: black; FONT-FAMILY: Verdana">EAR</span><span style="COLOR: black; FONT-FAMILY: 宋体">文件）</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">使用</span><span style="COLOR: black; FONT-FAMILY: Verdana">WLS Web </span><span style="COLOR: black; FONT-FAMILY: 宋体">服务</span><span style="COLOR: black; FONT-FAMILY: Verdana">WSDL</span><span style="COLOR: black; FONT-FAMILY: 宋体">并通过运行</span><span style="COLOR: black; FONT-FAMILY: Verdana">wsdl.exe</span><span style="COLOR: black; FONT-FAMILY: 宋体">生成一个</span><span style="COLOR: black; FONT-FAMILY: Verdana">.NetClient Stub</span><span style="COLOR: black; FONT-FAMILY: 宋体">。这一过程将生成一个</span><span style="COLOR: black; FONT-FAMILY: Verdana">.cs</span><span style="COLOR: black; FONT-FAMILY: 宋体">文件，该文件包含对应于</span><span style="COLOR: black; FONT-FAMILY: Verdana">WSDL</span><span style="COLOR: black; FONT-FAMILY: 宋体">提供的</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的方法定义。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">另外一步是在</span><span style="COLOR: black; FONT-FAMILY: Verdana">Stub</span><span style="COLOR: black; FONT-FAMILY: 宋体">中定义一个新的构造函数，并将</span><span style="COLOR: black; FONT-FAMILY: Verdana">WSL URL</span><span style="COLOR: black; FONT-FAMILY: 宋体">作为一个参数。这一步是必须的，因为</span><span style="COLOR: black; FONT-FAMILY: Verdana">wsdl.exe</span><span style="COLOR: black; FONT-FAMILY: 宋体">所生成的</span><span style="COLOR: black; FONT-FAMILY: Verdana">Stub</span><span style="COLOR: black; FONT-FAMILY: 宋体">在缺省情况下指向</span><span style="COLOR: black; FONT-FAMILY: Verdana">USDL URL</span><span style="COLOR: black; FONT-FAMILY: 宋体">中的本地主机。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Symbol">·<span style="FONT: 7pt 'Times New Roman'">                 </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">创建一个</span><span style="COLOR: black; FONT-FAMILY: Verdana">.NetClient </span><span style="COLOR: black; FONT-FAMILY: 宋体">类（另外一个</span><span style="COLOR: black; FONT-FAMILY: Verdana">.cs</span><span style="COLOR: black; FONT-FAMILY: 宋体">文件），该类实际上以</span><span style="COLOR: black; FONT-FAMILY: Verdana">WSDL URL</span><span style="COLOR: black; FONT-FAMILY: 宋体">作为构造函数参数。该类是一个代理类，它含有与</span><span style="COLOR: black; FONT-FAMILY: Verdana">Stub</span><span style="COLOR: black; FONT-FAMILY: 宋体">中所定义的相同的方法。</span><span style="COLOR: black; FONT-FAMILY: Verdana">.Net</span><span style="COLOR: black; FONT-FAMILY: 宋体">客户首先对</span><span style="COLOR: black; FONT-FAMILY: Verdana">Stub</span><span style="COLOR: black; FONT-FAMILY: 宋体">类进行了实例化，然后将方法的调用委托到</span><span style="COLOR: black; FONT-FAMILY: Verdana">Stub</span><span style="COLOR: black; FONT-FAMILY: 宋体">。</span><span style="FONT-SIZE: 7pt; COLOR: black; FONT-FAMILY: Verdana"></span></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="Normal" valign="top" bgcolor="#cccccc"><p style="TEXT-ALIGN: left" align="left"><span>  </span>.NET Server</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>.Net Client</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>WebLogic Server</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>WLS Web Service</p><p style="TEXT-ALIGN: left" align="left"><span> </span> using System;</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>namespace interop</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>{</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>/// &lt;summary&gt;</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>/// Client for StockTrade web service</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>/// &lt;/summary&gt;</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>public class StockTradeClient</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>{</p><p style="TEXT-ALIGN: left" align="left"><span>                                </span>public StockTradeClient()</p><p style="TEXT-ALIGN: left" align="left"><span>                                </span>{</p><p style="TEXT-ALIGN: left" align="left"><span>                                    </span>    // </p><p style="TEXT-ALIGN: left" align="left"><span>                                        </span>// TODO: Add constructor logic here</p><p style="TEXT-ALIGN: left" align="left"><span>                                        </span>//</p><p style="TEXT-ALIGN: left" align="left"><span>                                </span>}</p><p style="TEXT-ALIGN: left" align="left"><span>   </span>             static void Main()</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>{</p><p style="TEXT-ALIGN: left" align="left"><span>                                </span>string action = "BUY";</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>string symbol = "BEAS";</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>int quantity = 100;</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>StockTradeService stService = new StockTradeService();</p><p style="TEXT-ALIGN: left" align="left"><span>    </span>            Console.WriteLine("Stock Trade Service: ");</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>bool result = stService.execute(action,symbol, quantity);</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>Console.Write("Result of Stock Trade: ");</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>Console.WriteLine(result.ToString());</p><p style="TEXT-ALIGN: left" align="left"><span>              </span>                  }</p><p style="TEXT-ALIGN: left" align="left"><span>                </span>}</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>} </p></td></tr></tbody></table><h3><span style="FONT-FAMILY: 宋体">代码摘录</span><span style="FONT-FAMILY: 宋体">：</span><span>.NET</span><span style="FONT-FAMILY: 宋体">客户端</span><span></span></h3><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">上面摘录的的一段代码是对应于我们前面创建的</span><span style="COLOR: black; FONT-FAMILY: Verdana">Stock Trade Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的</span><span style="COLOR: black; FONT-FAMILY: Verdana">.NET</span><span style="COLOR: black; FONT-FAMILY: 宋体">客户端代码，该段代码是用与</span><span style="COLOR: black; FONT-FAMILY: Verdana">JAVA</span><span style="COLOR: black; FONT-FAMILY: 宋体">语言极为相似的</span><span style="COLOR: black; FONT-FAMILY: Verdana">C#</span><span style="COLOR: black; FONT-FAMILY: 宋体">语言开发的。文件名是</span><span style="COLOR: black; FONT-FAMILY: Verdana">“StockTradeClient.cs”</span><span style="COLOR: black; FONT-FAMILY: 宋体">。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">代码编写完成后，在</span><span style="COLOR: black; FONT-FAMILY: Verdana">.NET</span><span style="COLOR: black; FONT-FAMILY: 宋体">框架上部署</span><span style="COLOR: black; FONT-FAMILY: Verdana">.NET</span><span style="COLOR: black; FONT-FAMILY: 宋体">客户端，并且在</span><span style="COLOR: black; FONT-FAMILY: Verdana">WebLogic Server</span><span style="COLOR: black; FONT-FAMILY: 宋体">上部署</span><span style="COLOR: black; FONT-FAMILY: Verdana">WLS Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">，验证客户端是否能正确调用</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">下面的就是在</span><span style="COLOR: black; FONT-FAMILY: Verdana">WebLogic Server</span><span style="COLOR: black; FONT-FAMILY: 宋体">中显示的日志的格式：</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="Normal" valign="top" bgcolor="#cccccc"><p style="TEXT-ALIGN: left" align="left"><span>  </span>SELLING quantity: 300 of symbol:IBM</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>execute() in webservices.stock.trade webservice has been invoked with following</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>arguments:: action:SELL123 symbol:IBM quantity:300</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>INVALID action: SELL123</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>execute() in webservices.stock.trade webservice has been invoked with following</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>arguments:: action:SELL symbol:IBM quantity:300</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>SELLING quantity: 300 of symbol:IBM</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>execute() in webservices.stock.trade webservice has been invoked with following</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>arguments:: action:SELL123 symbol:IBM quantity:300</p><p style="TEXT-ALIGN: left" align="left"><span>  </span>INVALID action: SELL123</p></td></tr></tbody></table><h3><span style="FONT-FAMILY: 宋体"><br />结束语</span><span></span></h3><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">通过将所讨论的测试方法集成到</span><span style="COLOR: black; FONT-FAMILY: Verdana"> Web </span><span style="COLOR: black; FONT-FAMILY: 宋体">服务开发过程中，我们就可以确保</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">服务器能够良好处理可能类型和数量的客户端请求，而且</span><span style="COLOR: black; FONT-FAMILY: Verdana">Web Services</span><span style="COLOR: black; FONT-FAMILY: 宋体">的客户端也能正确地访问和检索服务所提供的任何数据。</span><span style="COLOR: black; FONT-FAMILY: Verdana"></span></p><p style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">您可以从开发流程中的任何一点开始实施所讨论的方法，但如果您较早的开始测试，那么您防止错误以及发现错误的能力就强。通常，错误发现得越早，其解决就越早，而且也越有可能避免因创建与有问题模块交互的代码或组件而在不经意中使问题变得更为糟糕的情况，也越有可能避免在其他服务器或者客户中重用有问题的模块。<br /><br /><br />注：<br />文章来自：<a href="http://dev2dev.bea.com.cn/techdoc/200408234.html">http://dev2dev.bea.com.cn/techdoc/200408234.html</a><br />作者：<a href="http://dev2dev.bea.com.cn/author/37.html">Abhijit Patil</a>, <a href="http://dev2dev.bea.com.cn/author/50.html">Seetharam Param</a><br /></span></p><img src ="http://www.cnitblog.com/xiaoyaocao/aggbug/16996.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/xiaoyaocao/" target="_blank">逍遥草</a> 2006-09-18 15:51 <a href="http://www.cnitblog.com/xiaoyaocao/archive/2006/09/18/16996.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web Service 技术概览（六）-- Web Service故障处理 </title><link>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7391.html</link><dc:creator>逍遥草</dc:creator><author>逍遥草</author><pubDate>Thu, 09 Mar 2006 02:04:00 GMT</pubDate><guid>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7391.html</guid><wfw:comment>http://www.cnitblog.com/xiaoyaocao/comments/7391.html</wfw:comment><comments>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7391.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/xiaoyaocao/comments/commentRss/7391.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/xiaoyaocao/services/trackbacks/7391.html</trackback:ping><description><![CDATA[<IFRAME align=right marginWidth=0 marginHeight=0 src="http://www.cnnet.com.cn/servlets/ad?Pool=tech_pip" frameBorder=0 noResize width=360 scrolling=no height=300></IFRAME>Web Service 的故障处理会是一件很困难的事情，因为很多方面都会发生问题。这篇文章描述了你可能会遇到的各种问题，并说明应如何来处理它们。特别的，我们将讨论如下问题： 
<P></P>
<UL>
<LI>回顾SOAP请求 
<LI>深入服务器端Visual Basic代码 
<LI>深入服务器端Visual C++代码 
<LI>跟踪SSL问题 
<LI>深入Favorites Service中的问题 </LI></UL><B>回顾SOAP请求</B><BR>当开发一个简单对象访问协议（SOAP）客户端应用程序或服务器终端时，有一大堆东西可能出错。例如，SOAP请求可能不符合Web Service 描述语言（WSDL）规范，或SOAPAction项是错的。为了调试这些问题，你需要一个工具来查看SOAP请求和消息交换。在Microsoft Windows平台上，你有两个很好的工具。如果你只是想要调试SOAP请求，你应该下载Microsoft SOAP Toolkit 2.0，得到SOAP跟踪工具（MsSoapT.exe）。当你想要查看整个HTTP信息，请去http://www.pocketsoap.com/下载tcpTrace。这两个工具是互补的。你应该怎样查看SOAP请求呢？<BR>这两个工具都是通过截取并发送请求来查看SOAP请求的。要截取请求信息，你必须让你的客户端使用跟踪工具正在监听的端口。假定你在客户端用一个WSDL文件来建立调用，你必须将该文件装载到你的机器上，并编辑服务部分。在一台机器上，我们有一个Web Service ，它的服务部分如下：<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>&lt;service name='ArticleDemo' &gt;<BR>&lt;port name='ExampleSoapPort' binding='wsdlns:ExampleSoapBinding'&gt;<BR>&lt;soap:address location='http://hopehubris/test/ArticleDemo.WSDL'/&gt;<BR>&lt;/port&gt;<BR>&lt;/service&gt;<BR></TD></TR></TBODY></TABLE><BR>上面这个部分规定了ArticleDemo这个Web Service 的SOAP终端在http://hopehubris/test/ArticleDemo.WSDL默认的HTTP端口监听，即80端口。为了从该端口监听来往的消息，你必须编辑该文件以监听本机上另一个端口。要监听8080端口，你应将文件做如下修改并保存：<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>&lt;service name='ArticleDemo' &gt;<BR>&lt;port name='ExampleSoapPort' binding='wsdlns:ExampleSoapBinding'&gt;<BR>&lt;soap:address<BR>location='http://localhost:8080/test/ArticleDemo.WSDL'/&gt;<BR>&lt;/port&gt;<BR>&lt;/service&gt;<BR></TD></TR></TBODY></TABLE><BR>经过以上改动，启动MsSoapT.exe或者tcpTrace.exe并告知它监听8080端口，然后将请求发向hopehubris的80端口（见图一和图二）<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-1b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-1s.gif" border=0></A><BR>点击小图放大</DIV><BR><B>图一 配置MSSoapT.exe</B><BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-2b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-2s.gif" border=0></A><BR>点击小图放大</DIV><BR><B>图二 配置tcpTrace.exe</B><BR>通过以上方法，你可以查看进出的请求了。当所有的通讯正常工作，你只需要调试SOAP消息时，MSSoapT.exe是一个很好的工具。图三中显示了正常的消息交换。<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-3b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-2s.gif" border=0></A><BR>点击小图放大</DIV><BR><B>图三 MSSoapT.exe中正常的交换</B><BR>现在，我们来讨论怎样使用这些工具来调试问题。你可能经常遇到的问题是一个终端可能消失或者迁移了。利用一些良好的错误处理机制，你可以会发现问题，但是怎样确定是什么来往消息能够确认问题是由不存在的Web Service 造成的呢？对于这个问题，tcpTrace.exe能很好的解决。图四中显示了这种情况--你从服务器处得到响应，表示它对于你请求的终端不能处理。<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-4b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-4s.gif" border=0></A><BR>点击小图放大</DIV><BR><B>图四 使用tcpTrace.exe查看HTTP请求</B><BR>当你开发SOAP客户端应用程序时，你可能发现产生了很多SOAP错误。可能的原因包含从传送坏数据到服务器端问题。有时候直接查看XML文件比将错误信息提取出来写进日志文件更容易。对于你产生的每一个错误，你会想办法让客户端去处理。但为了发现错误，使用跟踪工具是很有帮助的。查看原始XML文件，请使用MSSoapT.exe。为了显示它是怎样工作的，我们以一个SOAP调用为例，它将两个数字相加，并当地一个参数小于10时，强行返回一个SOAP错误。以下是5和20相加的SOAP请求：<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>&lt;?xml version="1.0" encoding="UTF-8"standalone="no" ?&gt;<BR>&lt;SOAP-ENV:Envelope<BR>SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"<BR>xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"&gt;<BR>&lt;SOAP-ENV:Body&gt;<BR>&lt;SOAPSDK1:AddNumbers<BR>xmlns:SOAPSDK1="http://tempuri.org/message/"&gt;<BR>&lt;arg1&gt;5&lt;/arg1&gt;<BR>&lt;arg2&gt;20&lt;/arg2&gt;<BR>&lt;/SOAPSDK1:AddNumbers&gt;<BR>&lt;/SOAP-ENV:Body&gt;<BR>&lt;/SOAP-ENV:Envelope&gt;<BR></TD></TR></TBODY></TABLE><BR>如果一切正常而且终端没有被破坏，我们希望返回25。但是，终端被破坏了，得到以下结果：<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>&lt;?xml version="1.0" encoding="UTF-8"standalone="no" ?&gt;<BR>&lt;SOAP-ENV:Envelope<BR>SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"<BR>xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"&gt;<BR>&lt;SOAP-ENV:Body&gt;<BR>&lt;SOAP-ENV:Fault&gt;<BR>&lt;faultcode&gt;SOAP-ENV:Client&lt;/faultcode&gt;<BR>&lt;faultstring&gt;AddNumbers&lt;/faultstring&gt;<BR>&lt;faultactor&gt;<BR>http://tempuri.org/action/Example.AddNumbers<BR>&lt;/faultactor&gt;<BR>&lt;detail&gt;<BR>&lt;mserror:errorInfo<BR>xmlns:mserror=<BR>"http://schemas.microsoft.com/soap-toolkit/faultdetail/error/"&gt;<BR>&lt;mserror:returnCode&gt;-2146828188&lt;/mserror:returnCode&gt;<BR>&lt;mserror:serverErrorInfo&gt;<BR>&lt;mserror:description&gt;<BR>The first number must be greater than 10<BR>&lt;/mserror:description&gt;<BR>&lt;mserror:source&gt;AddNumbers&lt;/mserror:source&gt;<BR>&lt;/mserror:serverErrorInfo&gt;<BR>&lt;mserror:callStack&gt;<BR>&lt;mserror:callElement&gt;<BR>&lt;mserror:component&gt;Client&lt;/mserror:component&gt;<BR>&lt;mserror:description&gt;<BR>The first number must be greater than 10<BR>&lt;/mserror:description&gt;<BR>&lt;mserror:returnCode&gt;<BR>-2147352567<BR>&lt;/mserror:returnCode&gt;<BR>&lt;/mserror:callElement&gt;<BR>&lt;mserror:callElement&gt;<BR>&lt;mserror:component&gt;<BR>WSDLOperation<BR>&lt;/mserror:component&gt;<BR>&lt;mserror:description&gt;<BR>Executing method AddNumbers failed<BR>&lt;/mserror:description&gt;<BR>&lt;mserror:returnCode&gt;<BR>-2147352567<BR>&lt;/mserror:returnCode&gt;<BR>&lt;/mserror:callElement&gt;<BR>&lt;/mserror:callStack&gt;<BR>&lt;/mserror:errorInfo&gt;<BR>&lt;/detail&gt;<BR>&lt;/SOAP-ENV:Fault&gt;<BR>&lt;/SOAP-ENV:Body&gt;<BR>&lt;/SOAP-ENV:Envelope&gt;<BR></TD></TR></TBODY></TABLE><BR>上面的错误提供了很多信息，可以帮助你发现问题的所在。从错误中可见，<B>WSDLOperation</B>组件发现<B>AddNumbers</B>方法失败。它还表明是客户端发生问题，而且问题是：第一个数必须大于10。图五中显示了MSSoapT.exe中这个错误是怎样的。<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-5b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-5s.gif" border=0></A><BR>点击小图放大</DIV><BR><B>图五 跟踪SOAP错误</B><BR>这些工具还有很多用途。你可以用它们来分析SOAP请求和响应。有时候，Web Service只有一个客户端。如果你有客户端的源代码，你可以修改终端，让它可以通过跟踪工具。这样，你可以利用Microsoft SOAP Toolkit的底层API来反过来设计WSDL文件或构建客户端程序。<BR><BR><B>其他跟踪方法</B><BR>MSSoapT.exe和tcpTrace.exe是查看SOAP请求甚至HTTP请求的优秀工具，但有的情况下，这些工具收效甚微。比如，如果你尝试发送SOAP请求给服务器，但是它的主机名不能解析，或者不能接受TCP连接，你就无法利用前面所述的两种跟踪工具了。另一种情况可能发生在你试图通过安全套接层（SSL）来进行SOAP通讯。MSSoapT.exe和tcpTrace.exe在SSL下是没有什么作用。所以，在这些情况下，可以使用以下方法：<BR>
<UL>
<LI><B>Microsoft Network Monitor</B>，它是监控网络数据包的一个管理工具。如果你安装了Windows 2000 Server中带的版本，你可以看到本机发送和接收的数据包。System Management Server中带的是完整版，它能够显示物理网络中所有的数据包。Network Monitor可以用来查看所有试图连接SOAP服务器的信息流。例如，当试图解析要连接的服务器主机名时，你可以看到DNS请求和响应。当与服务器建立连接时，你也可以看到TCP握手数据包。这可以告诉你TCP连接是否正常建立，还是服务器过早的重置了你的连接。你还可以看到数据包中的数据，这样就可以跟踪HTTP报文头和SOAP信封了，当然这在前面所述的两个工具中查看会更方便。Network Monitor不会显示发送到本机的数据流。而且，它虽然能够显示通过SSL连接的数据，但是那是加密的，所以查看其中的数据包内容是没有意义的。 
<LI>通过自定义的<B>ISAPI ReadRawData and SendRawData Filter</B>可以查看你的Web Service 器所有发送和接收的数据。这包括发向你的Web Service 的SOAP请求和响应。MSSoapT.exe 和tcpTrace.exe已经实现了通过ISAPI filter实现的许多功能，但有一个重要的例外：ISAPI filter可以查看SSL中传输的数据，因为它能工作在SSL加密/解密层之上。因此，如果你想要解决SSL中的问题，你可以看到其中HTTP和SOAP等数据。由于ISAPI filter处于较高的网络层次，你将看不到那些连接建立等Network Monitor提供的细节。想要知道如何编写ISAPI filter，请看开发ISAPI Filters一文。 </LI></UL><B>深入服务器端Visual Basic代码</B><BR>有时候，你需要调试你自己的代码以确定产生错误结果的原因。当调试Microsoft Visual Basic应用程序时，你必须按照KB：PRB:Error Occurs When You Debut a COM+ Component Under the Visual Basic IDE with an ASP Client中的步骤来处理。这篇文章只适用于Visual Basic集成开发环境下调试COM+组件。文章中第一条也适用于调试SOAP对象。为了节省你查看KB文章的时间，以下是其中一些相关内容的摘要：<BR>1. 在DCOM中创建VB ASP Debugging项：<BR>a. 打开写字板或其他文本编辑器，输入以下语句，这是大小写敏感的。<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>REGEDIT4<BR>[HKEY_CLASSES_ROOT\CLSID\{70F214BA-94E2-4bdf-8F30-32CB4A905E4D}]<BR>@="VB ASP Debugging"<BR>[HKEY_CLASSES_ROOT\CLSID\{70F214BA-94E2-4bdf-8F30-32CB4A905E4D}\LocalServer32]<BR>@="vb6.exe"<BR>[HKEY_CLASSES_ROOT\AppID\vb6.exe]<BR>"AppId"="{70F214BA-94E2-4bdf-8F30-32CB4A905E4D}"</TD></TR></TBODY></TABLE><BR>b.将文件保存为Vbaspdbg.reg。<BR>c.定位到保存该文件的文件夹，双击该文件（它会自动在Windows注册表中注册）。<BR>2． 在DCOM配置中，将Everyone账号的许可加入Visual Basic ASP debugging中。<BR>a.打开DCOMCNFG。在Start菜单中，按Run，在对话框中输入dcomcnfg。<BR>b. 在Distributed COM Configuration Properties页面中，按Application标签，从列表中选择VB ASP Debugging，然后按Properties。<BR>c. 在VB ASP Debugging Properties属性单中，按Securities标签，然后选中Use custom access permissions。按Edit。<BR>d. 在Registry Value Permissions窗口中，按Add，然后加入Everyone账号，允许Allow Access。<BR>e. 按OK，然后按Apply并退出Distributed COM Configuaration Properties页面。<BR>注意，这样做会给你的系统带来一些安全漏洞。请不要在你实际生产或对外的机器上这样调试。<BR>一旦完成以上步骤，当SOAP客户端调用COM对象时，你就可以调试它们了。如果重新build你的应用程序或设置断点时遇到问题，相关的COM对象可能已经在内存中了。要卸载这些对象，进入命令行，输入iisreset。它将使IIS和相关进程重启。在此过程中，DLL和COM对象就从内存中释放了。<BR><BR><B>深入服务器端的Visual C++代码</B><BR>在服务器端调试Microsoft Visual C++?代码比VB要容易得多。Visual C++让你能够连接到正在运行的进程中，所以你只要连接到需要调试的DLL运行所在的进程，你就可以设置断点，单步调试等等。但也有一些要注意的地方，让我们来看一下其中一部分问题。<BR>通常可以通过菜单操作，将Visual C++调试程序连接到运行的进程中去。在Visual C++编程环境中，选择Build，在选择Start Debug，然后再选Attach to Process。你可以看到Attach to Process对话框（见图一）并选择要调试的进程。一旦你连接上了，就可以打开源文件并设置断点，假如你的EXE或DLL的调试版本是在该进程中运行的，而且有debug symbol。<BR><BR><B>问题一：在对话框中没有进程列出！</B>这是Microsoft Visual Studio? 6.0 SP3或更早版本中的bug，请使用SP4或更高版本。另一个方法是，请确定Visual C++是你的默认调试器，然后在任务管理器中点击右键，选中想要调试的进程并从弹出菜单中选择Debug。<BR><BR><B>问题二：对话框只显示了桌面上运行的程序！</B>请确认你选中了Show System Processes。<BR><BR><B>问题三：我应该连接到什么进程？</B>如果你有一个组件在IIS中使用（就像SOAP Toolkit 2.0中DLL组件），它们默认运行在dllhost.exe进程中。不幸的是，也许会有很多这样的进程，你就不知道你的DLL到底运行在哪一个之中了。如果你刚刚启动了一个dllhost.exe实例，想要调试，它会在Visual C++的<B>Attach to Process</B>对话框中列在最上面。如果你的应用程序已经运行了一段时间了，通常你可以通过任务管理器中Processest标签下查看你一个DLLHOST版本占用了大量内存和CPU，以次猜测出是该进程。但是，如果你想要精确的知道你的DLL运行在哪一个进程中，你可以使用tlist.exe这个工具，通过安装在Windows 2000的光盘中\Support\Tools目录中的支持工具就可以得到它。然后，你在命令行中可以输入：<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>TLIST -m mydll.dll</TD></TR></TBODY></TABLE><BR>来得到加载了你的DLL的进程列表。你可以辨识出相应的dllhost.exe实例，然后连接上去。如果你的Web Service 运行所在的虚拟目录的应用程序安全性设置为低，它会在IIS的主进程inetinfo.exe中运行，而不是dllhost.exe。<BR>我们开发Favorites Service时遇到的一个重要问题就是调试SSFKeyCache服务，它不在IIS进程或者DLLHOST进程之中。我们用ATL将SSFKeyCache创建为系统服务。当你在调试模式下编译COM server系统服务工程时，它被注册为普通进程外COM server。如果问题只发生在第一次调用COM server的时候就没有什么问题，但是如果像我们在SSFKeyCache中那样要保留调用中的信息，你必须将它驻留在内存之中。因此，为了调试它，我们将SSFKeyCache编译为调试版本，然后将其重新注册为普通系统服务。在命令行中运行：<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>SSFKeyCache -Service</TD></TR></TBODY></TABLE><BR>然后，我们手工启动这个服务。请在命令行运行：<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>NET START SSFKEYCACHE<BR></TD></TR></TBODY></TABLE><BR>这样我们才能用Visual C++连接到运行的进程中，设置断点等等。如果不必要捕捉到SSFKeyCache组件第一个实例的创建，我们可以等待其他的调用，服务会自行启动的。<BR><BR><B>深入SSL问题</B><BR>当通过安全套接层连接到Web Service 时，你会遇到很多问题。要诊断这些错误有时候是很困难的，特别是如果你只是从SOAP工具中收到一些普通的TCP连接错误。通常发生的有四个问题，其中的三个可以通过在IE浏览器中连接WSDL文件中指定的地址来发现。<BR>SSL服务器证书没有安装。想要在你服务器上支持SSL，你首先要安装服务器证书。如果你没有安装，你不能连接到服务器上HTTP默认的SSL连接端口443。SOAP Toolkit 2.0会返回一个0x800A1518 (-2146822888)错误，表示连接错误。这也是其他三个SSL相关错误的错误代码。如果你在IE中试图浏览HTTPS开头的URL，你会得到一个标准的DNS出错页面。去掉"S"后再试一遍。如果你得到不同的出错信息，你就知道是服务器证书还没有安装。<BR>URL中的主机名同服务器证书中的名字不匹配。当你为Web Service 器创建服务器证书时，你必须确定其中的名字同用户访问时URL中的主机名一致。如果不一致，当你用IE访问时，你会看到一个<B>Security Alert</B>对话框，如图六所示。当证书已经正确安装，但使用localhost指定本地计算机时，也常常看到这个问题。要避免这个问题，请将WSDL文件中location元素指定为你的服务器证书中所使用的名字。<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-6b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-6s.gif" border=0></A><BR>点击小图放大</DIV><BR><B>图六 IE Security Alert对话框，它表示证书同站点名称不一致</B><BR><BR><B>证书颁发机构不是受信任的机构。</B>很多人都使用Microsoft Certificate Server来创建证书，安装到自己的机器上进行测试。这样可以比购买真正的得到全球广泛认证的服务器证书节约时间和费用。但是，当你成为自己的证书的认证机构时，网络中其他的机器并不信任你发布的证书。这些机器必须首先为你的认证机构安装根证书，然后才能通过安全套接层连到你的服务器。同样的，你可以通过在IE中用HTTPS URL指定Web Service，来确认是否有这个问题。如果证书颁发机构不是受信任的机构，你会看到和图6相似的对话框，除了左上角的图标会变成警告图示。你的认证机构的证书必须安装在想用SSL连接到你的服务器的所有计算机上。<BR><B>该证书机构不在受信任的本机证书列表中</B>。如果你在IE中连接到该Web Service ，没有看到Security Alert 对话框（即使重启IE也没有），但是你仍然无法通过ASP页面访问Web Service，这可能是一个更微妙的问题。当你安装证书认证机构的证书时，你可能将它加入到个人的证书认证列表中。而ASP页面是在IIS进程中的，不能访问你用户账号中的证书列表。为了使ASP页面能够通过SSL进行访问，请确定证书认证机构的证书是作为受信任的根证书安装在本机的证书列表之中。你可以打开mmc.exe，添加Certificates MMC插件并将证书认证机构的证书导入本机列表之中，成为受信任的根证书。这样问题就解决了。<BR>关于Favorites Services中安装SSL功能的具体步骤，请查阅Installing the Favorites Service<BR><BR><B>深入Favorites Service 中的问题</B><BR>如果你想使用<B>Favorites Service</B>并遇到了问题，你会怎么做呢？例如，你可能在登陆时会看到这样的消息："Favorites现在不能使用。请您的网站管理员查看日志中的详细信息"。这时应该怎么处理呢？<BR>首先，你应该按照消息中的指示去做。如果你在单机上进行了完整安装，那你就是网站管理员，所以你应该查看事件日志。Favorites Service（包括范例客户站点）在Application日志中记录事件，source是"Favorites Web Service"。出错消息如下所示：<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-7b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101e-7s.gif" border=0></A><BR>点击小图放大</DIV><BR><B>图七 Favorites Service日志范例</B><BR>你可能注意到图七中描述框的内容还有待改进。我们现在没有提供更好的日志功能。由于日志功能是由VB写的DLL实现的，因此很难使用C++工具来定制日志中的格式化字符串。当日志查看器无法正确显示信息时，就将传递给日志的字符串显示出来。在这里就是"/ssf/logon.asp: Nonsecure Logon request attempted."。这表明有人试图通过非SSL的连接方式进行登陆，所以用户名和密码没有经过加密。而Favorites Service是不会接受非SSL传递的登陆请求的。<BR>如果你怀疑你的日志中没有应该可以看到的日志记录，请你确认Application Event Log没有设置RestrictGuestAccess键。在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application中查看RestrictGuestAccess设置。默认状态下该键值为0，表示guess access是允许的。但是如果你对系统的安全性做过调整，或你的域安全策略在这方面有限制，那么这个设置会被启动。由于Favorites Service是运行在匿名账号下的，只有guest权限，如果RestrictGuestAccess设为1，你在事件日志中就看不到Favorites Service的事件了。<BR>有时候，你除了日志信息外还需要一些其他的信息。例如，你可能收到一个加入喜好的请求，但产生了一个SOAP错误，你想要得到关于这个请求的更多的信息。Favorites Service有一个审计日志记录了它所有的活动供你查看。审计信息是存放在SSF-Report数据库中的AuditLog表中的。你可以使用SQL Query Analyzer或在Microsoft SQL Server?的Enterprise Manager中选择<B>Return all rows</B>查看所有的信息。Actiontype字段可以通过ActionType表以更友好的名字表示。而description字段中会包含与请求相关的额外信息。<BR>怎样才能跟踪与请求相关的IP地址呢？你可能想要设置一些限制，或查看请求来自何方。审计日志中只告诉你时间，但没有IP地址。在http://www.coldrooster.com/，我们用IIS 日志来记录HTTP相关信息。为了跟踪日志记录中的请求的IP地址，我们要查看审计日志中的时间戳，在IIS日志中寻找相应的信息。通常在同一时间段中，不会有太多的请求同时发生。请记住，IIS日志默认是按格林尼治标准时间来记录时间戳的，所以你在做相应的查找时，必须做一些相应的时区转换。<BR>最后一个我们要讨论的问题与web farm有关，就像http://www.coldrooster.com中：我们的Web服务器上不仅有Favorites Service的虚拟目录，还有其他的虚拟目录，如SSFPublic，coldrooster.com目录等。这使问题变得复杂，因为如果要查找一个问题，它可能发生在三台机器中的任何一台。同样，当一个错误的请求发送过来，并不确定是哪一个服务器来处理的。请注意，在一台单机上是很容易查找问题的，当与内部Web请求可能相关，要到其他机器上去寻找问题时，就会有问题了。要同步所有机器上不同的事件是很困难的，但并不是不可实现的。<BR><BR><B>小结</B><BR>在这篇文章中，我们提供了一些Web Service故障检测和处理的方法，并以Favorites Service为例进行说明。这可以帮助解决一些你实际中遇到的问题。<img src ="http://www.cnitblog.com/xiaoyaocao/aggbug/7391.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/xiaoyaocao/" target="_blank">逍遥草</a> 2006-03-09 10:04 <a href="http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7391.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web Service 技术概览（五）--.NET中的Web service的开发</title><link>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7390.html</link><dc:creator>逍遥草</dc:creator><author>逍遥草</author><pubDate>Thu, 09 Mar 2006 02:02:00 GMT</pubDate><guid>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7390.html</guid><wfw:comment>http://www.cnitblog.com/xiaoyaocao/comments/7390.html</wfw:comment><comments>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7390.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/xiaoyaocao/comments/commentRss/7390.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/xiaoyaocao/services/trackbacks/7390.html</trackback:ping><description><![CDATA[.NET平台内建了对Web service的支持，包括Web service的构建和使用。 与其它开发平台不同，使用.NET平台，你不需要其他的工具或者SDK就可以完成Web service的开发了。.NET Framework本身就全面支持Web service，包括服务器端的请求处理器和对客户端发送和接受SOAP消息的支持。本节将带你用.NET创建和使用一个简单的Web service。<BR>要在.NET中创建Web service，你只需建立一个.asmx文件。这个文件中有一个WebService标签，包含Language和class两个属性，分别用于指定编程语言和Web service中暴露出的类。然后你就可以像平常一样编写你的类了。最后，在每个你想要暴露出的方法前面加一个System.Web.Services.WebMethodAttribute属性就可以了。最终代码类似于下面的程序清单。<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>'a WebService in VB.NET (calc_vb.asmx)<BR>&lt;%@WebService Language="VB"class="Calc" %&gt;<BR>Imports System.Web.Services<BR>Public Class Calc<BR>&lt;WebMethod()&gt; _<BR>Public Function Add(ByVal a As Double, _<BR>ByVal b As Double) As Double<BR>Return a + b<BR>End Function<BR>End Class<BR></TD></TR></TBODY></TABLE><BR>用浏览器来浏览这个.asmx文件，你可以得到一张测试这个Web service的页面。例如，你把calc_vb.asmx 文件放到了Web服务器的myService目录下，那么相应的URL就是：<BR>http://localhost/myService/calc_vb.asmx<BR>测试页如下图所示。这一页是自动生成的。它显示了Web service 的名字并列出了可以调用的方法。列表后面有一段文字，意思是你正在使用缺省的命名空间http://tempuri.org/，如果你想要发布这个Web service的话，最好换一个你自己的命名空间，以避免名字上的冲突。本书后面的部分将会讨论Web service 命名空间的问题。在第六章中，我还会介绍怎样使用.NET的属性来指定命名空间和其他一些东西。<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101c-1b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101c-1s.gif" border=0></A><BR>自动生成的Web service测试页，点击小图放大</DIV><BR>在测试页里点击Add方法，你会得到一个HTML表单，用来测试这个方法(见下图)。在这个表单里，Add方法所接受的所有参数都有一个相应的文本框。填好所有的参数，点击"Invoke"按钮，这个表单就会被提交到Web服务器。实际上，这就是通过HTTP GET的形式在调用Web service。得到的结果是一个如下的简单XML文档：<BR>&lt;double xmlns="http://tempuri.org/"&gt;158&lt;/double&gt;<BR>浏览下面这个URL，可以直接调用Add方法：<BR>http://localhost/myService/calc_vb.asmx/Add?a=123&amp;b=35<BR>如你所见，方法的名字是你所请求的资源(注意，这里是区分大小写的)，而函数中的每个参数都映射为查询字符串中的一个参数。这种形式对快速测试一个Web service 是非常方便的。不过，因为这种方式使用的是HTTP GET，所以它在数据类型和参数传递方向等方面都有一些局限。我们将在第六章中详细讨论这些局限。<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101c-2b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101c-2s.gif" border=0></A><BR>自动生成的Add方法测试页，点击小图放大</DIV><BR>回到前面的Web service测试页，我们还可以看到页面的顶部有一个Service Description链接。点击过去你就可以得到描述这个Web service的WSDL文档，如下图。在Web service的URL后面加上一个"WSDL"查询字符串，你也可以直接浏览到这一页：<BR>http://localhost/myService/calc_vb.asmx?wsdl<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101c-3b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101c-3s.gif" border=0></A><BR>点击小图放大</DIV><BR>Calc Web service的WSDL文档。注意，为了显示更多内容，所有的XML元素都已折叠起来。<BR>Calc Web service的WSDL文档。注意，为了显示更多内容，所有的XML元素都已折叠起来。<BR>要在.NET中调用一个Web service ，你需要先运行wsdl.exe工具。这个工具会从Web service中读出它的WSDL描述文档，生成一个可以调用这个Web service的代理类。例如，在命令行中执行下面的命令，可以生成Calc Web service的代理类： <BR>wsdl.exe /language:VB http://localhost/myService/calc_vb.asmx?wsdl<BR>程序清单1-2截取自生成的VB代理类源码。这个代理类继承自System.Web.Services.Protocols.SoapHttpClientProtocol类，并且暴露出一个Add方法，这个方法接收两个double型浮点数，返回一个double型浮点数。<BR>程序清单1 2 截取自wsdl.exe 生成的Web service代理类源代码<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>Imports System.Web.Services.Protocols<BR>'省略其他代码<BR>Public Class Calc<BR>Inherits SoapHttpClientProtocol<BR>'省略其他代码<BR>&lt;System.Diagnostics.DebuggerStepThroughAttribute(),_<BR>SoapDocumentMethodAttribute( _<BR>"http://tempuri.org/Add", _<BR>Use:=System.Web.Services.Description.SoapBindingUse.Literal,_<BR>ParameterStyle:= SoapParameterStyle.Wrapped)&gt;_<BR>Public Function Add(ByVal a As Double, ByValb As Double) As Double<BR>Dim results() As Object = Me.Invoke("Add",_<BR>New Object() {a, b})<BR>Return CType(results(0), Double)<BR>End Function<BR>'省略其他代码<BR>End Class<BR>此后的工作就非常简单了。要调用CalculatorWeb service，只需实例化一个Calc的代理对象，再调用它的Add方法：<BR>Dim ws As New Calc()<BR>Dim result As Double = ws.Add(20.5, 10.9)<BR>MessageBox.Show("结果是：" &amp;result.ToString)<BR></TD></TR></TBODY></TABLE><BR>实际上，代理类中的Add方法仅仅是通过.NET Framework的SoapHttpClientProtocol类来调用Web service，然后再把Web service 的返回值返回给调用者。 <BR>当然，除了上面的这些演示之外，.NET Web service的创建和调用还有很多的内容。不过，在深入这些细节之前，我们需要先理解Webservice里面的几个关键技术：XSD、SOAP和WSDL。<BR><img src ="http://www.cnitblog.com/xiaoyaocao/aggbug/7390.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/xiaoyaocao/" target="_blank">逍遥草</a> 2006-03-09 10:02 <a href="http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7390.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web Service 技术概览（四）--Web Service“四长两短” </title><link>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7389.html</link><dc:creator>逍遥草</dc:creator><author>逍遥草</author><pubDate>Thu, 09 Mar 2006 02:00:00 GMT</pubDate><guid>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7389.html</guid><wfw:comment>http://www.cnitblog.com/xiaoyaocao/comments/7389.html</wfw:comment><comments>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7389.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/xiaoyaocao/comments/commentRss/7389.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/xiaoyaocao/services/trackbacks/7389.html</trackback:ping><description><![CDATA[实际上，Web Service的主要目标是跨平台的可互操作性。为了达到这一目标，Web Service 完全基于XML（可扩展标记语言）、XSD（XML Schema）等独立于平台、独立于软件供应商的标准，是创建可互操作的、分布式应用程序的新平台。由此可以看出，在以下三种情况下，使用Web Service会带来极大的好处。 <BR><BR><STRONG>长项一： 跨<A href="http://www.ccidnet.com/school/dict/explain/F_809.html">防火墙</A>的通信</STRONG> <BR>如果应用程序有成千上万的用户，而且分布在世界各地，那么客户端和服务器之间的通信将是一个棘手的问题。因为客户端和服务器之间通常会有<A href="http://www.ccidnet.com/school/dict/explain/F_809.html">防火墙</A>或者代理服务器。在这种情况下，使用DCOM就不是那么简单，通常也不便于把客户端程序发布到数量如此庞大的每一个用户手中。传统的做法是，选择用浏览器作为客户端，写下一大堆ASP页面，把应用程序的中间层暴露给最终用户。这样做的结果是开发难度大，程序很难维护。 <BR><BR>
<DIV align=center><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/01-1.jpg"><BR><B>图1 通过Web Service集成应用程序</B></DIV><BR>举个例子，在应用程序里加入一个新页面，必须先建立好用户界面(Web页面)，并在这个页面后面，包含相应商业逻辑的中间层组件，还要再建立至少一个ASP页面，用来接受用户输入的信息，调用中间层组件，把结果格式化为HTML形式，最后还要把“结果页”送回浏览器。要是客户端代码不再如此依赖于HTML表单，客户端的编程就简单多了。 <BR><BR>如果中间层组件换成Web Service的话，就可以从用户界面直接调用中间层组件，从而省掉建立ASP页面的那一步。要调用Web Service，可以直接使用Microsoft SOAP Toolkit或.NET这样的SOAP客户端，也可以使用自己开发的SOAP客户端，然后把它和应用程序连接起来。不仅缩短了开发周期，还减少了代码复杂度，并能够增强应用程序的可维护性。同时，应用程序也不再需要在每次调用中间层组件时，都跳转到相应的“结果页”。 <BR><BR>从经验来看，在一个用户界面和中间层有较多交互的应用程序中，使用Web Service这种结构，可以节省花在用户界面编程上20%的开发时间。另外，这样一个由Web Service组成的中间层，完全可以在应用程序集成或其它场合下重用。最后，通过Web Service把应用程序的逻辑和数据“暴露”出来，还可以让其它平台上的客户重用这些应用程序。 <BR><BR><STRONG>长项二： 应用程序集成</STRONG> <BR>企业级的应用程序开发者都知道，企业里经常都要把用不同语言写成的、在不同平台上运行的各种程序集成起来，而这种集成将花费很大的开发力量。应用程序经常需要从运行在IBM主机上的程序中获取数据；或者把数据发送到主机或UNIX应用程序中去。即使在同一个平台上，不同软件厂商生产的各种软件也常常需要集成起来。通过Web Service，应用程序可以用标准的方法把功能和数据“暴露”出来，供其它应用程序使用。 <BR><BR>例如，有一个订单登录程序，用于登录从客户来的新订单，包括客户信息、发货地址、数量、价格和付款方式等内容；还有一个订单执行程序，用于实际货物发送的管理。这两个程序来自不同软件厂商。一份新订单进来之后，订单登录程序需要通知订单执行程序发送货物。通过在订单执行程序上面增加一层Web Service，订单执行程序可以把“Add Order”函数“暴露”出来。这样，每当有新订单到来时，订单登录程序就可以调用这个函数来发送货物了。 <BR><BR><STRONG>长项三： B2B的集成</STRONG> <BR>用Web Service集成应用程序，可以使公司内部的商务处理更加自动化。但当交易跨越供应商和客户、突破公司的界限时会怎么样呢？跨公司的商务交易集成通常叫做B2B集成。 <BR><BR>Web Service是B2B集成成功的关键。通过Web Service，公司可以把关键的商务应用“暴露”给指定的供应商和客户。例如，把电子下单系统和电子发票系统“暴露”出来，客户就可以以电子的方式发送订单，供应商则可以以电子的方式发送原料采购发票。当然，这并不是一个新的概念， EDI(电子文档交换)早就是这样了。但是，Web Service的实现要比EDI简单得多，而且Web Service运行在Internet上，在世界任何地方都可轻易实现，其运行成本就相对较低。不过，Web Service并不像EDI那样，是文档交换或B2B集成的完整解决方案。Web Service只是B2B集成的一个关键部分，还需要许多其它的部分才能实现集成。 <BR><BR>用Web Service来实现B2B集成的最大好处在于可以轻易实现互操作性。只要把商务逻辑“暴露”出来，成为Web Service，就可以让任何指定的合作伙伴调用这些商务逻辑，而不管他们的系统在什么平台上运行，使用什么开发语言。这样就大大减少了花在B2B集成上的时间和成本，让许多原本无法承受EDI的中小企业也能实现B2B集成。 <BR><BR><STRONG>长项四： 软件和数据重用</STRONG> <BR>软件重用是一个很大的主题，重用的形式很多，重用的程度有大有小。最基本的形式是源代码模块或者类一级的重用，另一种形式是二进制形式的组件重用。 <BR><BR>
<DIV align=center><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/01-2.jpg"><BR><B>图2 用Web Service集成各种应用中的功能，为用户提供一个统一的界面</B></DIV><BR>当前，像表格控件或用户界面控件这样的可重用软件组件，在市场上都占有很大的份额。但这类软件的重用有一个很大的限制，就是重用仅限于代码，数据不能重用。原因在于，发布组件甚至源代码都比较容易，但要发布数据就没那么容易，除非是不会经常变化的静态数据。 <BR><BR>Web Service在允许重用代码的同时，可以重用代码背后的数据。使用Web Service，再也不必像以前那样，要先从第三方购买、安装软件组件，再从应用程序中调用这些组件；只需要直接调用远端的Web Service就可以了。举个例子，要在应用程序中确认用户输入的地址，只需把这个地址直接发送给相应的Web Service，这个Web Service 就会帮你查阅街道地址、城市、省区和邮政编码等信息，确认这个地址是否在相应的邮政编码区域。Web Service 的提供商可以按时间或使用次数来对这项服务进行收费。这样的服务要通过组件重用来实现是不可能的，那样的话你必须下载并安装好包含街道地址、城市、省区和邮政编码等信息的数据库，而且这个数据库还是不能实时更新的。 <BR><BR>另一种软件重用的情况是，把好几个应用程序的功能集成起来。例如，要建立一个局域网上的门户站点应用，让用户既可以查询联邦快递包裹，查看股市行情，又可以管理自己的日程安排，还可以在线购买电影票。现在Web上有很多应用程序供应商，都在其应用中实现了这些功能。一旦他们把这些功能都通过Web Service “暴露”出来，就可以非常容易地把所有这些功能都集成到你的门户站点中，为用户提供一个统一的、友好的界面。 <BR><BR>将来，许多应用程序都会利用Web Service，把当前基于组件的应用程序结构扩展为组件/Web Service 的混合结构，可以在应用程序中使用第三方的Web Service 提供的功能，也可以把自己的应用程序功能通过Web Service 提供给别人。两种情况下，都可以重用代码和代码背后的数据。 <BR><BR>从以上论述可以看出，Web Service 在通过Web进行互操作或远程调用的时候是最有用的。不过，也有一些情况，Web Service根本不能带来任何好处。 <BR><BR><STRONG>短处一： 单机应用程序</STRONG> <BR>目前，企业和个人还使用着很多桌面应用程序。其中一些只需要与本机上的其它程序通信。在这种情况下，最好就不要用Web Service，只要用本地的API就可以了。COM非常适合于在这种情况下工作，因为它既小又快。运行在同一台服务器上的服务器软件也是这样。最好直接用COM或其它本地的API来进行应用程序间的调用。当然Web Service 也能用在这些场合，但那样不仅消耗太大，而且不会带来任何好处。 <BR><BR><STRONG>短处二： 局域网的同构应用程序</STRONG> <BR>在许多应用中，所有的程序都是用VB或VC开发的，都在Windows平台下使用COM，都运行在同一个局域网上。例如，有两个服务器应用程序需要相互通信，或者有一个Win32或WinForm的客户程序要连接局域网上另一个服务器的程序。在这些程序里，使用DCOM会比SOAP/HTTP有效得多。与此相类似，如果一个.NET程序要连接到局域网上的另一个.NET程序，应该使用.NET remoting。有趣的是，在.NET remoting中，也可以指定使用SOAP/HTTP来进行Web Service 调用。不过最好还是直接通过TCP进行RPC调用，那样会有效得多。 <BR><BR>总之，只要从应用程序结构的角度看，有别的方法比Web Service 更有效、更可行，那就不要用Web Service。<img src ="http://www.cnitblog.com/xiaoyaocao/aggbug/7389.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/xiaoyaocao/" target="_blank">逍遥草</a> 2006-03-09 10:00 <a href="http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7389.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web Service 技术概览（三）--典型的Web Service结构</title><link>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7388.html</link><dc:creator>逍遥草</dc:creator><author>逍遥草</author><pubDate>Thu, 09 Mar 2006 01:59:00 GMT</pubDate><guid>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7388.html</guid><wfw:comment>http://www.cnitblog.com/xiaoyaocao/comments/7388.html</wfw:comment><comments>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7388.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/xiaoyaocao/comments/commentRss/7388.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/xiaoyaocao/services/trackbacks/7388.html</trackback:ping><description><![CDATA[典型的Web Service结构。 <BR><BR>不管你的Web service是用什么工具，什么语言写出来的，只要你用SOAP协议通过HTTP来调用它，总体结构都应如下图所示。通常，你用你自己喜欢的语言(如VB 6或者VB.NET)来构建你的Web service，然后用SOAP Toolkit或者.NET的内建支持来把它暴露给Web客户。于是，任何语言，任何平台上的客户都可以阅读其WSDL文档，以调用这个Web service。客户根据WSDL描述文档，会生成一个SOAP请求消息。Web service都是放在Web服务器 (如IIS) 后面的，客户生成的SOAP请求会被嵌入在一个HTTP POST请求中，发送到Web服务器来。Web服务器再把这些请求转发给Web service请求处理器。对VB 6程序来说，Web service请求处理器是一个与SOAP Toolkit组件协同工作的ASP页面或ISAPI extension。而对VB.NET程序来说，Web service请求处理器则是一个.NET Framework自带的ISAPI extension。请求处理器的作用在于，解析收到的SOAP请求，调用Web service，然后再生成相应的SOAP应答。Web服务器得到SOAP应答后，会再通过HTTP应答的方式把它送回到客户端。<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101b-1b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101b-1s.gif" border=0></A><BR>典型的Web service结构，点击小图放大</DIV><BR><BR><B>远程过程调用(RPC)与消息传递</B><BR>Web service本身实际是在实现应用程序间的通信。我们现在有两种应用程序通信的方法：RPC(远程过程调用)和消息传递。使用RPC的时候，客户端的概念是调用服务器上的远程过程，通常方式为实例化一个远程对象并调用其方法和属性。RPC强调的是远程对象和它的界面，即属性、方法和调用时的参数。DCOM和.NET远程访问都是RPC的例子。 <BR>消息传递一般是在耦合度更低的系统中。消息传递的概念是，客户端向服务器发送消息，然后等待服务器的回应。消息传递系统强调的是消息的发送和回应，而不是远程对象的界面。由于是基于消息的系统，客户端和服务器之间的耦合度比RPC方法更低。<BR>RPC系统试图达到一种位置上的透明性：服务器暴露出远程对象的接口，而客户端就好像在使用本地使用的这些对象的接口一样，这样就隐藏了底层的信息，客户端也就根本不需要知道对象是在哪台机器上。例如，你在VB 6中通过DCOM调用一个远程对象，你的代码看起来就与调用本地对象一样。而消息传递则不同，它强调传递的东西是什么，但不管消息传递过去后干什么。客户不需要知道服务器是怎么实现的，以及消息是怎么被处理的。<BR>我们已经说过，你可以建立一个消息服务器，根据收到的消息来调用对象。这是通过消息传递方式有效的实现了RPC。如果客户仍然以消息的思维方式来进行操作，那么你可以把它叫做消息传递。但如果客户以远程对象的思维方式来进行操作，那么你就应该把它叫做RPC。 <BR>如果你想实现一个基于XML的消息传递系统，大量的工作将集中在处理XML请求和应答消息上。虽然VB 6和VB.NET中，帮助你建立Web Service的工具已经做了许多对XML消息进行处理的工作，但毕竟所有的数据都是用XML的形式收发的，许多情况下你还是需要对消息进行一些自己的处理。深入理解XML和XML Schema对于有效地实现XML消息系统是至关重要的。<BR><BR><BR><B>建立Web Service</B><BR>我知道你现在已经很心急的想要写点代码，看看Web service到底是什么样的了。那么我们现在就介绍怎样用VB 6和VB.NET实际做出一个Web service来。本节的目的只是向你展示一下这些工具的功能，而不是深入地讲解Web service的工作原理。本书后面的章节会向你慢慢说明Web service以及Microsoft SOAP Toolkit和.NET等工具的内部原理的。<BR><BR><B>使用SOAP Toolkit</B><BR>Microsoft的SOAP Toolkit V2帮助你把COM组件变成Web service。这套工具分为三大主要部分：SoapClient是一个用于调用Web service的COM组件；SoapServer 是一个处理SOAP请求和返回SOAP应答的组件；还有一个WSDL向导，它可以把你的type library转换成WSDL文档，以暴露给Web service的客户。<BR>假设你有一个COM组件，暴露出一个GetTemperature方法：<BR>Public Function GetTemperature(ByVal zipcode As String, _<BR>ByVal celsius As Boolean) As Single<BR><BR>要把这个组件变成一个Web service，你可以使用WSDL向导。给出你要转换的组件后，向导会要你选择你想暴露出的方法，指出生成的Web service所在的URL(如http://localhost/Temperature/)，以及你希望用ASP还是ISAPI做你的请求处理器(如图1-2)。然后向导还会问你生成的WSDL和ASP文件应该放在那个目录下。<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101b-1b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101b-1s.gif" border=0></A><BR>使用SOAP Toolkit向导来转换COM组件，点击小图放大</DIV><BR><BR>现在该调用这个Web service了。方法是在VB或其他任何可以使用COM的语言里调用SoapClient组件。下面这段代码演示了怎样调用Webservice中的GetTemperature方法：<BR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=580 borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6>Dim soap As MSSOAPLib.SoapClient<BR>Set soap = New MSSOAPLib.SoapClient<BR>soap.mssoapinit _<BR>"http://localhost/Temperature/Temperature.wsdl"<BR>MsgBox ("气温是： " &amp; _<BR>soap.GetTemperature("20171", False))</TD></TR></TBODY></TABLE><BR>首先调用mssoapinit，把WSDL文档的URL传给SoapClient。WSDL文档的URL就是你在WSDL向导中给出的URL加上〈Service名字.wsdl〉。一旦初始化完成，SoapClient就得到了Web service的所有方法，你就可以直接调用这些方法了。<BR><img src ="http://www.cnitblog.com/xiaoyaocao/aggbug/7388.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/xiaoyaocao/" target="_blank">逍遥草</a> 2006-03-09 09:59 <a href="http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7388.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web Service 技术概览（二）--什么时候应该使用Web Service</title><link>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7387.html</link><dc:creator>逍遥草</dc:creator><author>逍遥草</author><pubDate>Thu, 09 Mar 2006 01:58:00 GMT</pubDate><guid>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7387.html</guid><wfw:comment>http://www.cnitblog.com/xiaoyaocao/comments/7387.html</wfw:comment><comments>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7387.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/xiaoyaocao/comments/commentRss/7387.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/xiaoyaocao/services/trackbacks/7387.html</trackback:ping><description><![CDATA[现在我将列举三种情况，在这三种情况下，你将会发现使用Web service会带来极大的好处。此后，我还会举出不应该使用Web service的一些情况。<BR><BR><B>跨越<A href="http://www.ccidnet.com/school/dict/explain/F_809.html">防火墙</A>的通信</B><BR>如果你的应用程序有成千上万的用户，而且他们都分布在世界各地，那么客户端和服务器之间的通信将是一个棘手的问题。那是因为客户端和服务器之间通常都会有<A href="http://www.ccidnet.com/school/dict/explain/F_809.html">防火墙</A>或者代理服务器。在这种情况下，你想使用DCOM就不是那么简单了，而且，通常你也不愿意把你的客户端程序发布到如此庞大数量的每一个用户手中。于是，你最终选择了用浏览器作为客户端，写下一堆ASP页面，把应用程序的中间层暴露给最终用户。结果呢？运气好的话，只是开发难度大了一些，运气不好的话，就会得到一个根本无法维护的应用程序。 <BR>想象一下你应该怎么在你的应用程序里面加入一个新的页面：你必须先建立好用户界面(Web页面)，以及在这个页面后面，包含相应商业逻辑的中间层组件。这还不够，你还要再建立至少一个ASP页面，用来接受用户输入的信息，调用中间层组件，把结果格式化为HTML形式，最后还要把"结果页"送回浏览器。要是客户端代码不再如此依赖于HTML表单，客户端的编程不就简单多了吗？还有，建立ASP页面的那一步可以省略掉吗？ <BR>当然。如果你的中间层组件是Web service的话，你完全可以从用户界面直接调用中间层组件，从而省掉建立ASP页面的那一步。要调用Web service，你可以直接使用Microsoft SOAP Toolkit或.NET这样的SOAP客户端，也可以使用你自己开发的SOAP客户端，然后把它和你的应用程序连接起来。这样做，不仅可以缩短开发周期，还可以减少代码的复杂度，并增强整个应用程序的可维护性。同时，你的应用程序也不再需要在每次调用中间层组件时，都跳转到相应的"结果页"了。<BR>以我的经验来看，在一个用户界面和中间层有较多交互的应用程序中，使用Web service这种结构，可以轻松的节省花在用户界面编程上的20%的开发时间。这样做还有另一个好处，就是你将得到一个由Web service组成的中间层，这一层是完全可以在应用程序集成或其他场合下被重用的。最后，通过Web service把你的应用程序的逻辑和数据暴露出来，还可以让其它平台上的客户重用你的应用程序。<BR><BR><B>应用程序集成</B><BR>企业级的应用程序开发者都知道，企业里经常都要把用不同语言写成的在不同平台上运行的各种程序集成起来，而这种集成将花费很大的开发的力量。你的应用程序经常都需要从运行在古老的IBM主机上的程序中获取数据；或者再把数据发送到主机或UNIX应用程序中去。即使是在同一个平台上，不同的软件厂商生产的各种软件也常常需要集成起来。通过Web service，应用程序可以用标准的方法把功能和数据暴露出来，供其它的应用程序使用。<BR>例如，你有一个订单登录程序，用于登录从客户来的新订单，包括客户信息、发货地址、数量、价格和付款方式等信息。同时，你还有一个订单执行程序，用于实际货物发送的管理。这两个程序是来自不同软件厂商的。一份新订单进来之后，订单登录程序需要通知订单执行程序发送货物。通过在订单执行程序上面增加一层Web service，订单执行程序可以把"AddOrder"函数暴露出来。这样，每当有新订单到来时，订单登录程序就可以调用这个函数来发送货物了。如下图。<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101d-1b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101d-1s.gif" border=0></A><BR>通过Web service集成应用程序，点击小图放大</DIV><BR><B>B2B的集成</B><BR>用Web service集成应用程序，可以使你公司内部的商务处理更加自动化。但当交易跨越了你的供应商和客户，突破了公司的界线时又会怎么样呢？跨公司的商务交易集成通常叫做B2B集成。<BR>Web service是B2B集成成功的关键。通过Web service，你的公司可以把关键的商务应用暴露给指定的供应商和客户。例如，把你的电子下单系统和电子发票系统暴露出来，你的客户就可以以电子的方式向你发送购货订单，而你的供应商则可以以电子的方式把原料采购的发票发送给你。当然，这并不是一个新的概念：电子文档交换(EDI)早就是这样了。Web service和EDI之间的主要区别在于，Web service的实现要比EDI简单得多，而且Web service是运行在Internet上的，在世界任何地方都可轻易实现，这样其运行成本就相对较低。不过，Web service并不像EDI那样，是文档交换或B2B集成的一套完整的解决方案。Web service只是B2B集成的一个关键部分，还需要许多其它的部分才能完成这个集成。<BR>用Web service来实现B2B集成的最大好处在于可以轻易实现互操作性。只要把你的商务逻辑暴露出来，成为Web service，你就可以让任何指定的合作伙伴轻松的调用你的商务逻辑，而不管他们的系统在什么平台上运行，使用的是什么开发语言。这样就大大减少了花在B2B集成的上的时间和成本。这样的低成本让许多原本无法承受EDI的投资成本的中小企业也能实现B2B集成。<BR><BR><B>软件重用</B><BR>软件重用是一个很大的主题，它有很多的形式和程度。最基本的形式是源代码模块或者类一级的重用。另一种形式是二进制形式的组件重用。当前，像表格控件或用户界面控件这样的可重用软件组件在市场上都占有很大的份额。但这类软件的重用都有一个很严重的限制：重用仅限于代码，而数据不能被重用。原因在于你可以很轻易的发布组件甚至源代码，但要发布数据就没那么容易了，除非那些数据都是不会经常变化的静态数据。<BR>而Web service允许你在重用代码的同时，重用代码后面的数据。使用Web service，你不再像以前那样，要先从第三方购买、安装软件组件，再从你的应用程序中调用这些组件。你只需要直接调用远端的Web service就可以了。举个例子，你想在你的应用程序中确认用户输入的邮件地址，那么，你只需把这个地址直接发送给相应的Web service，这个Web service 就会帮你查阅街道地址、城市、省区和邮政编码等信息，确认这个地址的确在相应的邮政编码区域。Web service 的提供商可以按时间或使用次数来对这项服务进行收费。这样的服务要通过组件重用来实现是不现实的，因为那样的话你必须下载并安装好包含街道地址、城市、省区和邮政编码等信息的数据库，而且这个数据库还是不能实时更新的。<BR>另一种软件重用的情况是把好几个应用程序的功能集成起来。例如，你想要建立一个局域网上的门户站点应用，让用户既可以查询他们的联邦快递包裹，察看股市行情，又可以管理他们的日程安排，还可以在线购买电影票。现在Web上有很多应用程序供应商，都在其应用中实现了上面的这些功能。一旦他们把这些功能都通过Web service 暴露出来，你就可以非常轻易地把所有这些功能都集成到你的门户站点中，为用户提供一个统一的、友好的界面。如下图。<BR>
<DIV align=center><A href="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101d-2b.gif" target=_blank><IMG src="http://www0.ccidnet.com/tech/guide/2001/11/01/image/20011101d-2s.gif" border=0></A><BR>点击小图放大</DIV><BR>用Web service来集成各种应用中的功能，为用户提供一个统一的界面<BR>许多应用程序都会利用Web service，把当前基于组件的应用程序结构扩展为组件和Web service 的混合结构。你也可以在应用程序中使用第三方的Web service 提供的功能。你还可以把你自己的应用程序的功能通过Web service 提供给别人。所有这些情况下，你都可以重用代码和代码后面的数据。总之，Web service 将是软件重用的一种非常有力的形式。<BR><BR><B>什么时候不应该使用Web Service</B><BR>一个对Web service的完整介绍还应该包括什么时候不该用Web service。经过前面的介绍，我们知道了Web service 在通过Web进行互操作或远程调用的时候是最有用的。不过，还有许多情况，Web service根本不能给你带来任何好处。<BR><BR><B>单机应用程序</B><BR>目前，我们还有很多桌面应用程序是供商用和个人使用的。其中一些只需要与运行在本机上的其他程序通信。在这种情况下，我们最好就不要再用Web service ，只要用本地的API就可以了。COM非常适合于在这种情况下工作，因为它既小又快。运行在一台服务器上的服务器软件也是这样：最好直接用COM或其他本地的API来进行应用程序间的调用。当然Web service 也能用在这些情况下，但那样不仅消耗太大，而且不会给你带来任何好处。<BR><BR><B>局域网上的同构应用程序</B><BR>在许多应用中，你所有的程序都是用VB或VC开发的，都在Windows平台下使用COM，都运行在同一个局域网上。例如，你有两个服务器应用程序需要相互通信，或者你有一个Win32或WinForm的客户程序要连接到局域网上的另一个服务器程序。在这些程序里使用DCOM会比SOAP/HTTP有效的多。类似的，如果你的一个.NET程序要连接到LAN上的另一个.NET程序，那么你应该使用.NET remoting。有趣的是，在.NET remoting中，你也可以指定使用SOAP/HTTP来进行Web service 调用。不过最好还是直接通过TCP进行RPC调用，那样会有效得多。总之，只要你从应用程序结构的角度看来，有别的方法比Web service 更有效，更可行，那就不要再用Web service。<BR><BR><B>总结</B><BR>Web service是创建可互操作的分布式应用程序的新平台。Web service 的主要目标是跨平台的可互操作性。为了达到这一目标，Web service 是完全基于XML、XSD等独立于平台、独立于软件供应商的标准的。 <BR>Web service在应用程序跨平台和跨网络进行通信的时候是非常有用的。Web service适用于应用程序集成、B2B集成、代码和数据重用，以及通过Web进行客户端和服务器的通信的场合。<BR>当然，Web service也不是万能的，你不能到处滥用Web service。在有些情况下，Web service 会降低应用程序的性能，而不会带来任何好处。例如，一台机器或一个局域网里面运行的同构应用程序就不应该用Web service 进行通信。<BR><img src ="http://www.cnitblog.com/xiaoyaocao/aggbug/7387.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/xiaoyaocao/" target="_blank">逍遥草</a> 2006-03-09 09:58 <a href="http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7387.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web Service 技术概览（一）--什么是Web Service</title><link>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7386.html</link><dc:creator>逍遥草</dc:creator><author>逍遥草</author><pubDate>Thu, 09 Mar 2006 01:55:00 GMT</pubDate><guid>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7386.html</guid><wfw:comment>http://www.cnitblog.com/xiaoyaocao/comments/7386.html</wfw:comment><comments>http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7386.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/xiaoyaocao/comments/commentRss/7386.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/xiaoyaocao/services/trackbacks/7386.html</trackback:ping><description><![CDATA[你可能早就听说过Web service了，你也可能已经对Web service有一些概念了。一时间，好像所有的计算机期刊、书籍和网站都开始提及Web service。然而，当前大多数对Web service的介绍都没能清楚的说明Web service到底是什么。他们只是鼓吹Web service是多么多么的好，简直就像是在做广告。在本文中会讲清楚两件事：Web service到底是什么；在什么情况下你应该使用Web service。<BR><BR><B>分布式应用程序和浏览器</B><BR>研究一下当前的应用程序开发，你会发现一个绝对的倾向：人们开始偏爱基于浏览器的瘦客户应用程序。这当然不是因为瘦客户能够提供更好的用户界面，而是因为它能够避免花在桌面应用程序发布上的高成本。发布桌面应用程序成本很高，一半是因为应用程序安装和配置的问题，另一半是因为客户和服务器之间通信的问题。 <BR>传统的Windows富客户应用程序使用DCOM来与服务器进行通信和调用远程对象。配置好DCOM使其在一个大型的网络中正常工作将是一个极富挑战性的工作，同时也是许多IT工程师的噩梦。事实上，许多IT工程师宁愿忍受浏览器所带来的功能限制，也不愿在局域网上去运行一个DCOM。在我看来，结果就是一个发布容易，但开发难度大而且用户界面极其受限的应用程序。极端的说，就是你花了更多的资金和时间，却开发出从用户看来功能更弱的应用程序。不信？问问你的会计师对新的基于浏览器的会计软件有什么想法：绝大多数商用程序用户希望使用更加友好的Windows用户界面。<BR>关于客户端与服务器的通信问题，一个完美的解决方法是使用HTTP协议来通信。这是因为任何运行Web浏览器的机器都在使用HTTP协议。同时，当前许多<A href="http://www.ccidnet.com/school/dict/explain/F_809.html">防火墙</A>也配置为只允许HTTP连接。 <BR>许多商用程序还面临另一个问题，那就是与其他程序的互操作性。如果所有的应用程序都是使用COM或.NET语言写的，并且都运行在Windows平台上，那就天下太平了。然而，事实上大多数商业数据仍然在大型主机上以非关系文件(VSAM)的形式存放，并由COBOL语言编写的大型机程序访问。而且，目前还有很多商用程序继续在使用C++、Java、Visual Basic和其他各种各样的语言编写。现在，除了最简单的程序之外，所有的应用程序都需要与运行在其他异构平台上的应用程序集成并进行数据交换。这样的任务通常都是由特殊的方法，如文件传输和分析，消息队列，还有仅适用于某些情况的的API，如IBM的"高级程序到程序交流(APPC)"等来完成的。在以前，没有一个应用程序通信标准，是独立于平台、组建模型和编程语言的。只有通过Web Service，客户端和服务器才能够自由的用HTTP进行通信，不论两个程序的平台和编程语言是什么。<BR><BR><B>什么是Web Service</B><BR>对这个问题，我们至少有两种答案。从表面上看，Web service 就是一个应用程序，它向外界暴露出一个能够通过Web进行调用的API。这就是说，你能够用编程的方法通过Web来调用这个应用程序。我们把调用这个Web service 的应用程序叫做客户。例如，你想创建一个Web service ，它的作用是返回当前的天气情况。那么你可已建立一个ASP页面，它接受邮政编码作为查询字符串，然后返回一个由逗号隔开的字符串，包含了当前的气温和天气。要调用这个ASP页面，客户端需要发送下面的这个HTTP GET请求：<BR>http://host.company.com/weather.asp?zipcode=20171<BR><BR>返回的数据就应该是这样：<BR>21,晴<BR><BR>这个ASP页面就应该可以算作是Web service 了。因为它基于HTTP GET请求，暴露出了一个可以通过Web调用的API。当然，Web service 还有更多的东西。<BR>下面是对Web service 更精确的解释： Web services是建立可互操作的分布式应用程序的新平台。作为一个Windows程序员，你可能已经用COM或DCOM建立过基于组件的分布式应用程序。COM是一个非常好的组件技术，但是我们也很容易举出COM并不能满足要求的情况。<BR>Web service平台是一套标准，它定义了应用程序如何在Web上实现互操作性。你可以用任何你喜欢的语言，在任何你喜欢的平台上写Web service ，只要我们可以通过Web service标准对这些服务进行查询和访问。<BR><BR><B>新平台</B><BR>Web service平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性，Web service平台必须提供一套标准的类型系统，用于沟通不同平台、编程语言和组件模型中的不同类型系统。在传统的分布式系统中，基于界面(interface)的平台提供了一些方法来描述界面、方法和参数（译注：如COM和COBAR中的IDL语言）。同样的，Web service平台也必须提供一种标准来描述Web service，让客户可以得到足够的信息来调用这个Web service。最后，我们还必须有一种方法来对这个Web service进行远程调用。这种方法实际是一种远程过程调用协议(RPC)。为了达到互操作性，这种RPC协议还必须与平台和编程语言无关。下面几个小节就简要介绍了组成Web service平台的这三个技术。<BR><BR><B>XML和XSD</B><BR>可扩展的标记语言(XML)是Web service平台中表示数据的基本格式。除了易于建立和易于分析外，XML主要的优点在于它既是平台无关的，又是厂商无关的。无关性是比技术优越性更重要的：软件厂商是不会选择一个由竞争对手所发明的技术的。<BR>XML解决了数据表示的问题，但它没有定义一套标准的数据类型，更没有说怎么去扩展这套数据类型。例如，整形数到底代表什么？16位，32位，还是64位？这些细节对实现互操作性都是很重要的。W3C制定的XML Schema(XSD)就是专门解决这个问题的一套标准。它定义了一套标准的数据类型，并给出了一种语言来扩展这套数据类型。Web service平台就是用XSD来作为其数据类型系统的。当你用某种语言(如VB.NET或C#)来构造一个Web service时，为了符合Web service标准，所有你使用的数据类型都必须被转换为XSD类型。你用的工具可能已经自动帮你完成了这个转换，但你很可能会根据你的需要修改一下转换过程。在第二章中，我们将深入XSD，学习怎样转换自定义的数据类型(例如类)到XSD的类型。<BR><BR><B>SOAP</B><BR>Web service建好以后，你或者其他人就会去调用它。简单对象访问协议(SOAP)提供了标准的RPC方法来调用Web service。实际上，SOAP在这里有点用词不当：它意味着下面的Web service是以对象的方式表示的，但事实并不一定如此：你完全可以把你的Web service写成一系列的C函数，并仍然使用SOAP进行调用。SOAP规范定义了SOAP消息的格式，以及怎样通过HTTP协议来使用SOAP。SOAP也是基于XML和XSD的，XML是SOAP的数据编码方式。第三章我们会讨论SOAP，并结识SOAP消息的各种元素。<BR><BR><B>WSDL</B><BR>你会怎样向别人介绍你的Web service有什么功能，以及每个函数调用时的参数呢？你可能会自己写一套文档，你甚至可能会口头上告诉需要使用你的Web service的人。这些非正式的方法至少都有一个严重的问题：当程序员坐到电脑前，想要使用你的Web service的时候，他们的工具(如Visual Studio)无法给他们提供任何帮助，因为这些工具根本就不了解你的Web service。解决方法是：用机器能阅读的方式提供一个正式的描述文档。Web service描述语言(WSDL)就是这样一个基于XML的语言，用于描述Web service及其函数、参数和返回值。因为是基于XML的，所以WSDL既是机器可阅读的，又是人可阅读的，这将是一个很大的好处。一些最新的开发工具既能根据你的Web service生成WSDL文档，又能导入WSDL文档，生成调用相应Web service的代码。<img src ="http://www.cnitblog.com/xiaoyaocao/aggbug/7386.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/xiaoyaocao/" target="_blank">逍遥草</a> 2006-03-09 09:55 <a href="http://www.cnitblog.com/xiaoyaocao/archive/2006/03/09/7386.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>