开发者社区


项目管理 | IT/商务管理 | 职涯
首页 - 管理和职涯
管理&职涯
全文搜索:   

使用.Net, Java或者MS SOAP Toolkit 创建Web服务
作者:
2001-08-20 14:12:14


本文将介绍如何使用下列三种语言中的任一种建立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("+=", 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 ? " " + 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过程快乐!

声明:
Builder.com.cn(原ZDNet China应用开发频道)原创文章版权所有,未经许可严禁转载,且不构成投资建议。
近期相关报道:
实用技术文档
J2me XML
C/C++ C#
Java Oracle
Mysql .Net
VB.NET CSS
SQL Server 数据库
SQL UNIX
Linux Jsp
PHP Perl
Javascript IIS
XHTML ColdFusion
ASP/ASP.NET Apache
AJAX
订阅技术邮件
订阅"技术圈"杂志!请在下面选择您感兴趣的专题,填写e-mail地址,然后按订阅按钮:
应用开发管理
VS.NET 周刊
Database 周刊
WEB Service周刊
JAVA 周刊
IT 认证
Windows服务器周刊
互联网开发
当Windows Server 2008专家得5000元现金大奖
CNET NETWORKS 中国: 爱卡汽车网 | CNET科技资讯网 | e询网 | CWEEK | 蜂鸟网 | GameSpot China | 个人电脑 | PChome | SPN | 网友世界 | ZDNet China | 中关村在线
CNET NETWORKS 美国: BNET | CNET.com | CNET Download.com | CNET News.com | CNET Reviews | CNET Shopper.com | GameSpot | MP3.com | mySimon | Release 1.0 | Search.com | TechRepublic | TV.com | Webshots | ZDNet
Copyright (c) CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
ZDNet 公司标识是 CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号