您的位置:首页 > 编程语言 > ASP

JAVA+AXIS客户端调用Asp.net Web Service过程中遇到的问题及解决方法

2008-05-28 14:08 1306 查看
背景:公司与某运营商合作,运营商提供了接口文档,在文档中规定了数据流是双向的,运营商和公司之间的通讯采用Web Service方式,双方互为客户端和服务器端。这次遇到的问题,就是运营商的客户端调用我公司服务端的Web Service时出现的情况。需要特别说明的是:运营商有几十家合作伙伴,所以客户端的代码是不能因为某一家合作伙伴而修改的,各合作伙伴的WEB SERVICE开发环境也不相同,大部分都是用JAVA语言开发,而我公司是用VS2005开发的。
过程:
涉及的接口文档部分如下:
用户数据同步(syncUserData):

Index
Parameter Name
Req
Type
Size
Description
1
Mobile
M
String
21
用户号码
2
SPID
M
String
21
合作方标识
3
Service
M
String
21
业务代码
4
Action
M
Integer
4
用户操作
5
Time
M
String
14
时间戳 YYYYMMDDhhmmss
6
Desc
M
String
255
原因描述
7
Terminal
M
String
4
终端类型
运营商客户端采用:JAVA JDK 1.5+AXIS实现的Web Service客户端调用,并提供了具体的调试例子:


package smp.webservice.client;




import java.rmi.RemoteException;




import javax.xml.namespace.QName;


import javax.xml.rpc.ServiceException;




import org.apache.axis.client.Call;


import org.apache.axis.client.Service;






public class ServiceClient ...{


public int syncUserData(String Mobile, String SPID, String Service, Integer Action, String Time, String Desc, String terminal, String serviceEndPoint)




throws Exception ...{


Object result=null;




try ...{


Call call = this.invokeFunction("syncUserData", serviceEndPoint);




result=call.invoke(new Object[] ...{ Mobile, SPID, Service, Action, Time, Desc, terminal });




} catch (Exception e) ...{


throw e;


}






try...{


return ((Integer)result).intValue();




}catch(Exception e)...{


return Integer.parseInt(((String)result));


}


}




public Call invokeFunction(String operationName, String serviceEndPoint)




throws ServiceException ...{


Service service = ServiceInstance.getInstance();


Call call = (Call) service.createCall();


call.setTargetEndpointAddress(serviceEndPoint);


call.setOperationName(new QName(operationName));


return call;


}






/** *//**


* test the client method


*/




public static void main(String[] args) ...{


ServiceClient sc = new ServiceClient();


String endPoint = "http://127.0.0.1/WebTest/Service.asmx";






try ...{


int i=sc.syncUserData("13312345678", "3735127", "834621", new Integer(8), "20080101120000", "desc","9",endPoint);




System.out.println("result: " + i);




} catch (Exception e) ...{


e.printStackTrace();


}


}


}



其中endPoint的值是用于调用我本地的.net开发的WEB服务地址。
我用asp.net中的C#语言生成了WEBSERVICE,但JAVA客户端调用会报错,后用AXIS中自带的抓包工具Axis Tcp Monitor对客户端的调用(此时调用的是运营商供测试用的WEB SERVICE,JAVA语言的)进行了抓包,结果如下:


POST /axis/services/SPService HTTP/1.0


Content-Type: text/xml; charset=utf-8


Accept: application/soap+xml, application/dime, multipart/related, text/*


User-Agent: Axis/1.2


Host: 127.0.0.1:8081


Cache-Control: no-cache


Pragma: no-cache


SOAPAction: ""


Content-Length: 1208




<?xml version="1.0" encoding="UTF-8"?>


<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">


<soapenv:Body>


<syncUserData soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">


<arg0 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">13312345678</arg0>


<arg1 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">3735127</arg1>


<arg2 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">834621</arg2>


<arg3 href="#id0"/>


<arg4 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">20080101120000</arg4>


<arg5 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">desc</arg5>


<arg6 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">9</arg6>


</syncUserData>


<multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">8</multiRef>


</soapenv:Body>


</soapenv:Envelope>

发现参数名称都是arg0、arg1-arg6,而且int型参数arg3是通过href属性来实现的。查资料后得知AXIS客户端调用.Net是需要设置SoapDocumentService参数的。最后经过反复实验,终于用下面的C#代码成功处理了此客户端的请求:


using System;


using System.Web;


using System.Web.Services;


using System.Web.Services.Protocols;


using System.Web.Services.Description;




[WebService(Namespace = "www.microsoft.com")]


[SoapDocumentService(RoutingStyle = SoapServiceRoutingStyle.RequestElement)]


[WebServiceBinding(ConformsTo = WsiProfiles.None)]


public class Service : System.Web.Services.WebService




...{




public Service () ...{




//Uncomment the following line if using designed components


//InitializeComponent();


}




[SoapRpcMethod(Action = "syncUserData",RequestNamespace="")]


public int syncUserData([SoapElement("arg0")] string Mobile, [SoapElement("arg1")] string SPID,


[SoapElement("arg2")] string Service, [SoapElement("arg3")] int Action, [SoapElement("arg4")] string Time,


[SoapElement("arg5")] string Desc, [SoapElement("arg6")] string Terminal)




...{


//处理过程省略……


return 0;


}


}

代码中:

SoapDocumentService属性:主要是用于JAVA+AXIS客户端调用.net服务端时使用的,具体的原因,可以网上查到。

WebServiceBinding(ConformsTo = WsiProfiles.None):因为上面SoapDocumentService属性的设置,所以此WEBSERVICE已经不符合微软默认的“‘WSI 基本概要’1.1 版”。

SoapRpcMethod属性:主要是因为客户端为了调用不同合作伙伴的WEB SERVICE,所以在JAVA语句call.setOperationName(new QName(operationName));中只设置了方法名称,而没有设置命名空间。.net 服务端为了处理这种情况下的请求,必须在本属性中设置RequestNamespace=""。这里的处理是非常重要的!

[SoapElement("arg0")] ……:是对请求进行XML序列化处理,把实际请求中的参数名称arg0映射到我自己定义的名称Mobile中。

有人可能认为在WEB 服务开始阶段设置[WebService(Namespace = "")]不也可以让命名空间设为空吗?为什么要在SoapRpcMethod属性中设置。这是因为在这个案例中,必须用到SoapRpcMethod属性,而使用此属性后,就不能设置[WebService(Namespace = "")],不然调用时服务端就会报错。具体原因,我还不是十分了解,如果有高手能解释这个原因,我将拭目以待:)。

还有一个情况就是,在调试过程中经常会发现,因为参数中有一个int型的数据(请参考抓包数据),所以往往string型的数据都能读出来了,这个int型的数据却总是为0 (读不出正确的值),所以上面的c#代码中的SoapRpcMethod属性就是解决这个问题的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐