2002-09-13 14:20
使用.Net, Java或者MS SOAP Toolkit 创建Web服务
本文将介绍如何使用下列三种语言中的任一种建立web服务以及客户端程序:.NET,MS SOAP Tookkit和Java.但是本文的主旨还是要告诉你如何使用上面提到的语言来建立web服务的客户端程序.
在不久以前.NET被发布了而且我们中的许多人开始急着编写ASP.NET web站点,C#程序或是Web Services.我当时真的惊讶于人们能够使用.NET相对容易的编写web服务.我以前曾用MS SOAP Toolkit和Apache SOAP for Java编写过一些web服务.然后有人要求我用不同的语言为这些web服务编写客户端程序.这被事实证明了是不容易的.虽然SOAP现在已经成为标准,但是web服务的不同实现情况有时使得与其它SOAP的互联性很差,如果不是不可能的话.
我的例子程序是只有一个方法--addNumbers的非常简单的web服务.你可能已经猜出来了,它能够将两个数字相加然后返回结果.这个程序的名字叫Hello2其源代码附在本文上.
STK 服务和客户端
首先让我们使用MS SOAP Toolkit,ASP
监听程序和一个ISAPI监听程序来编写一个Web 服务.
Visual Basic类中的addNumbers方法是:
Public Function addNumbers(ByVal NumberOne As Double, ByVal
NumberTwo As Double) As Double
addNumbers = NumberOne +
NumberTwo
End Function
用WSDLGen.exe向导力可以生成ISAPI监听器,ASP监听器或是同时产生两者(当然也可以分开产生).我的选择是同时产生ASP和ISAPI监听器,所以我将我的WSDL文件分别命名Hello2ASP.WSDL
和Hello2Isapi.WSDL.
现在燃我们为这个Hello2 web服务写一些客户端.
STK 客户端
第一个客户端是一个Visual
Basic客户端程序,使用SOAP Toolkit中高层的API.创建一个VB工程并添加一个窗体和按钮.下面的代码在按钮被点击的时候执行.
Private Sub cmdDoTest_Click()
Const WS_URL = "http://localhost/Hello2/Hello2Isapi.WSDL"
Dim objHello2ISapi As SoapClient
Dim nResult As Double,
NumberOne As Double, NumberTwo As Double
On Error GoTo catch_err
Set objHello2ISapi = New
SoapClient
Call objHello2ISapi.mssoapinit(WS_URL)
NumberOne = 10
NumberTwo = 25
nResult =
objHello2ISapi.addNumbers(NumberOne, NumberTwo)
MsgBox nResult
cleanup:
Set objHello2ISapi = Nothing
Exit
Sub
catch_err:
MsgBox Err.Description
Resume
cleanup
End Sub
你可以发现客户端非常简单而且没有什么疑难.所有建立SOAP请求消息和解析返回的SOAP消息的过程被隐藏了,程序员无法看见.WS_URL是服务的URL.SOAP
Toolkit中高层的API需要一个WSDL文件所以这个URL指向一个这样的WSDL文件.你提供哪一个并不重要,虽然使用ISAPI监听器的性能要好一些.
Java客户端
我们为Hello2服务程序编写的第二个客户端程序是一个Java程序.我对这个程序使用了Apache
SOAP 2.1.你可以免费从http://xml.apache.org/soap/index.html下载.
ASP监听器所使用的Java类程序如下:
import java.io.*;
import java.util.*;
import
java.net.*;
import org.w3c.dom.*;
import
org.apache.soap.util.xml.*;
import org.apache.soap.*;
import
org.apache.soap.encoding.*;
import
org.apache.soap.encoding.soapenc.*;
import
org.apache.soap.rpc.*;
import
org.apache.soap.transport.http.SOAPHTTPConnection;
public class testClient {
public static void main(String[] args) throws Exception {
URL url = new URL ("http://localhost/Hello2/Hello2.asp");
SOAPMappingRegistry smr = new SOAPMappingRegistry
();
StringDeserializer sd = new StringDeserializer
();
smr.mapTypes (Constants.NS_URI_SOAP_ENC, new QName ("", "Result"),
null, null, sd);
// 创建传输路径和参数
SOAPHTTPConnection st = new
SOAPHTTPConnection();
// 创建调用
Call call = new Call
();
call.setSOAPTransport(st);
call.setSOAPMappingRegistry
(smr);
call.setTargetObjectURI ("http://tempuri.org/message/");
call.setMethodName("addNumbers");
call.setEncodingStyleURI
("http://schemas.xmlsoap.org/soap/encoding/");
Vector params = new Vector();
params.addElement(new
Parameter("NumberOne", Double.class, "10", null));
params.addElement(new
Parameter("NumberTwo", Double.class, "25",
null));
call.setParams(params);
Response resp = null;
try {
resp = call.invoke (url, "http://tempuri.org/action/Hello2.addNumbers");
}
catch (SOAPException e)
{
System.err.println("Caught SOAPException (" + e.getFaultCode () + "): "
+ e.getMessage ());
return;
}
// 检查返回值
if (resp != null &&
!resp.generatedFault()) {
Parameter ret =
resp.getReturnValue();
Object value = ret.getValue();
System.out.println ("Answer--> " + value);
}
else
{
Fault fault = resp.getFault ();
System.err.println ("Generated
fault: ");
System.out.println (" Fault Code = " +
fault.getFaultCode());
System.out.println (" Fault String = " +
fault.getFaultString());
}
}
}
正如你所看见的url变量指向ASP监听器.要将Java客户端指向ISAPI监听器只需要做如下修改:
URL url
= new URL ("http://localhost/Hello2/Hello2Isapi.wsdl");
.NET客户端
现在是时候为我们的Hello2
web服务写一个.NET客户端了.必须为我们的服务用 .NET Framework Beta 2
的WSD.exe工具来生成一个代理类.运行下面的命令.
wsdl http://localhost/Hello2/Hello2Isapi.wsdl
它将生成文件Hello2Isapi.cs.这是一个用C#(它是缺省的语言)写成的.NET代理类.你可以查到wsdl.exe的参数来生成用VB.NET或者其它语言写成的代理.现在用下面的命令编译代理
csc.exe /t:library Hello2Isapi.cs
可以编写.NET客户端了,它使用代理类来访问Hello2 web服务.下面是C#客户端的代码.
using
System;
public class Hello2ISapiClient {
public static void
Main() {
Hello2Isapi srv = new Hello2Isapi();
double res = 0, num1
= 10, num2 = 25;
res = srv.addNumbers(num1, num2);
Console.WriteLine("{0}+{1}={2}", num1, num2,
res);
}
}
用Hello2IsapiClient.cs
/reference:Hello2Isapi.dll编译客户端然后和Hello2IsapiClient一起运行它.
现在我们有了一个MS SOAP
Toolkit web服务程序和三个客户端,分别用:SOAP Toolkit, Java 和.NET 写成.
用Apache SOAP编写Java服务器端和客户端
让我们继续用Apache
SOAP来编写Java语言的同样的web 服务.下面是服务器端:
package samples.MyService;
import java.util.*;
import org.w3c.dom.*;
import
org.apache.soap.util.xml.*;
public class MyService {
public double addNumbers(double
num1, double num2) {
return num1+num2;
}
}
我将我的服务取名为MyService并将它添加到samples包里.这样你就不必在Tomcat服务器里添加上下文.只需要用下面的启用描述文件将这个服务添加到SOAP里:
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"
id="urn:myservice-service"
checkMustUnderstands="false">
<isd:provider type="java"
scope="Application" methods="addNumbers">
<isd:java
class="samples.MyService.MyService"
static="false"/>
</isd:provider>
</isd:service>
我不会在这里解释如何将Apache SOAP设置成Tomcat因为在Apache
SOAP文件里有足够的指导.
Apache
SOAP客户端
我们可以为这个服务编写客户端了.第一个是用Java写的.下面是源代码:
package
samples.MyService;
import java.io.*;
import java.util.*;
import
java.net.*;
import org.w3c.dom.*;
import
org.apache.soap.util.xml.*;
import org.apache.soap.*;
import
org.apache.soap.encoding.*;
import
org.apache.soap.encoding.soapenc.*;
import
org.apache.soap.rpc.*;
public class client {
public static void main(String[]
args) throws Exception {
if (args.length != 3
&&
(args.length != 4 ||
!args[0].startsWith("-")))
{
System.err.println("Usage:");
System.err.println("
java " + client.class.getName() +
" [-encodingStyleURI] SOAP-router-URL
nameToLookup");
System.exit (1);
}
// 处理参数
int offset = 4 - args.length;
String
encodingStyleURI = args.length == 4
? args[0].substring(1)
:
Constants.NS_URI_SOAP_ENC;
URL url = new URL(args[1 -
offset]);
Double num1 = new Double(args[2 - offset]),
num2 = new
Double(args[3 - offset]);
SOAPMappingRegistry smr = new
SOAPMappingRegistry();
BeanSerializer beanSer = new
BeanSerializer();
System.out.println(encodingStyleURI);
System.out.println(url);
System.out.println(num1);
System.out.println(num2);
// 建立调用
Call call = new Call();
call.setSOAPMappingRegistry(smr);
call.setTargetObjectURI("urn:MyService");
call.setMethodName("addNumbers");
call.setEncodingStyleURI(encodingStyleURI);
Vector params = new Vector();
params.addElement(new Parameter("num1", Double.class, num1,
null));
params.addElement(new Parameter("num2", Double.class, num2,
null));
call.setParams(params);
// 启动调用过程
Response resp;
long nErrors = 0;
Calendar cal =
Calendar.getInstance();
Date startTime = cal.getTime(),
endTime;
try {
resp = call.invoke(url, "");
}
catch
(SOAPException e) {
System.out.println("i=" +
i);
System.err.println("Caught SOAPException (" +
e.getFaultCode()
+ "): " +
e.getMessage());
return;
}
// 检查返回值
if (!resp.generatedFault()) {
Parameter
ret = resp.getReturnValue();
Object value = ret.getValue();
//System.out.println(value != null ? "\n" + value : "I don't
know.");
}
else {
Fault fault = resp.getFault();
System.err.println("Generated fault:
");
System.out.println (" Fault Code = " +
fault.getFaultCode());
System.out.println (" Fault String = " +
fault.getFaultString());
}
cal = Calendar.getInstance();
endTime =
cal.getTime();
System.out.println("Start
time="+startTime);
System.out.println("End
time="+endTime);
System.out.println ("Errors=" + nErrors);
}
}
如你所见,代码是非常直观的.应该没有什么问题因为我们使用了相同的SOAP库.一个STK客户端的代码如下:
STK
Client
在高层次的和低层次的客户端程序里都存在错误因为在Apache SOAP for
Java里需要xsi:类型.
.NET客户端
因为同样的问题.NET客户端也不会正常工作.
.NET服务和客户端
.NET Framework Beta 2
是最新的技术而且在Bata
2版本到最终版本发布可能还会有改动.在Beta2发布的时候主要的改变已经完成了.微软已经警告开发者有可能发生改动,所以这也就不奇怪了.
使用.NET编写一个web服务是很简单的而且可以用几种方法完成.我选择在ASMX文件里用C#编写我的web服务程序.下面是文件的内容.
using
System;
using System.Web.Services;
[WebService(Namespace="http://www.catalin.com/webservices/")]
public class MyService: WebService {
[
WebMethod(Description="return the sum of two
numbers")]
[System.Web.Services.Protocols.SoapRpcMethodAttribute(
"http://www.catalin.com/webservices/addNumbers",
RequestNamespace="http://www.catalin.com/webservices/",
ResponseNamespace="http://www.catalin.com/webservices/")]
public double addNumbers(double numberOne, double numberTwo)
{
return numberOne + numberTwo;
}
}
使用ASMX文件的好处是不需要进行编译,所以可以很快的使用这个程序.将文件放到IIS下的一个虚拟路径里.你可以用IE和http://localhost/testdotnetws/myservice.asmx .NET 客户端来测试这个服务程序.为这个服务编写一个客户端与我们前面写的.NET程序类似.在生成代理文件的时候将WSDL文件设置成http://localhost/testdotnetws/myservice.asmx?WSDL.这也是.NET framework用命令行产生WSDL文件的方式.
STK客户端
使用高层次的API会更快一些但是有一些问题我无法解决所以我使用了低层次的API.客户端程序并不复杂.唯一的技巧是使.NET服务对RPC形式的调用可用.感谢Christian
Weyer帮我解决了这个问题.看一看web服务程序的代码并注意我们方法的System.Web.Services.Protocols.SoapRpcMethodAttribute属性.没有这个属性的话,.NET中程序对话的缺省类型就是消息了.
Java客户端
在java客户端中你需要将url改成如下所示:
URL url = new URL ("http://localhost/aspnet_test/myservice/myservice.asmx");
编译运行
我希望这次对web服务世界的简短历程能够帮助你们那些致力于web服务开发的人.
祝你的SOAP过程快乐!