Android 调用.Net WCF服务 .

本来以为在java平台上用axis2生成了客户端代理类然后移植到Android平台上就好了。没想到在移植过程中出现了很多问题。说明JVM和android的DVM差距还是很大的。

JVM执行的是class文件,而DVM执行的是dex文件。

在eclipse里面开发Android程序的时候在编译时会把jar包里面的class一个个编译成DVM可执行的dex文件。当然,有个前提是jar包是放在source folder里面的。这样eclipse才会在编译程序的时候将jar包编译到apk文件中去。要不然虽然本地eclipse不会报错,但是在模拟器中会报错NoClassDefFound。

而且有的jar包是不能被dexdump.exe正确转换成dex文件的。这样就导致这个jar包不能用,后果是整个程序都不能正确运行。

我在将axis2移植到Android平台上去的时候有一些jar包转换不了。然后网上找了很多资料,都没人解决这个问题。希望如果有人解决了能共享一下下。

后来实在不行了,看网上说在Android平台都用ksoap2来调用Web Service。自己觉得解决不了axis2的问题。于是只能改变方向。学习了一下ksoap2。在ksoap2调用WCF服务的时候也出现了很多问题。好在后来慢慢都解决了。现在将我遇到的问题和解决的方案都写下来,供其他也碰到这些问题的人参考。

下面列举一下我碰到的问题和解决方案

1.调用是参数的说明

view plaincopy to clipboardprint?

  1. static String NameSpace="http://tempuri.org/";
  2. static String URL="https://10.0.2.2:9001/test";
  3. static String SOAP_ACTION="http://tempuri.org/ITestService/GetUser";
  4. static String MethodName="GetUser";

Namespace 是你设置的服务命名空间,一般没有设置就是http://tempuri.org/

URL是你服务暴露的地址,通过这个地址可以获取wsdl。在android里面127.0.0.1代表的是模拟器的地址,而10.0.0.2代表的才是电脑的127.0.0.1。所以如果是自己本机做WCF服务器的话,程序里面应该这么设置。

SOAP_ACTION是你的wsdl里面相对应的方法的地址。

MethodName就是SOAP_ACTION最后面的那个指明ACTION的方法名。

2.参数传递 复杂对象

服务里面不可避免的是会传递参数,但是在可能在wcf服务端可能解析不了你传的参数。通过tcptrace截取soap后发现是参数的namespace不对应的原因。下面是一个例子

服务端代码:

view plaincopy to clipboardprint?

  1. User ITestService.GetUser(User u)
  2. {
  3. User user = new User();
  4. user.UId = "Server:" + u.UId;
  5. user.UName = "Server:" + u.UName;
  6. return user;
  7. }

User类:

view plaincopy to clipboardprint?

  1. [DataContract]
  2. public class User
  3. {
  4. [DataMember]
  5. public string UId;
  6. [DataMember]
  7. public string UName;
  8. }

android客户端代码如下:

view plaincopy to clipboardprint?

  1. SoapObject requet=new SoapObject(NameSpace,MethodName);
  2. PropertyInfo perPropertyInfo=new PropertyInfo();
  3. User user=new User();
  4. user.setUId("123");
  5. user.setUName("cch");
  6. perPropertyInfo.setName("u");
  7. perPropertyInfo.setValue(user);
  8. perPropertyInfo.setType(User.class);
  9. requet.addProperty(perPropertyInfo);
  10. SoapSerializationEnvelope envelope=new SoapSerializationEnvelope(SoapEnvelope.VER11);
  11. envelope.addMapping(User.NAMESPACE,"User",User.class);//register 这个很重要
  12. envelope.setOutputSoapObject(requet);
  13. envelope.dotNet=true;
  14. AndroidHttpTransport transport=new AndroidHttpTransport (URL);
  15. ClientUtil.SetCertification();  //设置证书
  16. try {
  17. transport.call(SOAP_ACTION,envelope);
  18. //
  19. SoapObject response=(SoapObject)envelope.getResponse();
  20. //
  21. //PraseXML_SF(response);
  22. ((TextView)findViewById(R.id.txt01)).setText(String.valueOf(response.toString()));
  23. } catch (IOException e) {
  24. // TODO Auto-generated catch block
  25. e.printStackTrace();
  26. } catch (XmlPullParserException e) {
  27. // TODO Auto-generated catch block
  28. e.printStackTrace();
  29. }

android端也有一个User类,这个类是继承的BaseObject,BaseObject实现KvmSerializable接口

先BaseObject:

view plaincopy to clipboardprint?

  1. package CCH.Model;
  2. import org.ksoap2.serialization.KvmSerializable;
  3. import org.ksoap2.serialization.SoapObject;
  4. public abstract class BaseObject implements KvmSerializable
  5. {
  6. public static final String NAMESPACE = "http://schemas.datacontract.org/2004/07/TestService";
  7. //public static final String NAMESPACE = "http://schemas.datacontract.org/2004/07/HL7.Base.Struct";
  8. public BaseObject() {
  9. super();
  10. }
  11. }

然后是User类

view plaincopy to clipboardprint?

  1. package CCH.Model;
  2. import java.util.Hashtable;
  3. import org.ksoap2.serialization.PropertyInfo;
  4. public class User extends BaseObject
  5. {
  6. private String UId;
  7. private String UName;
  8. public Object getProperty(int index) {
  9. // TODO Auto-generated method stub
  10. switch (index) {
  11. case 0:
  12. return UId;
  13. case 1:
  14. return UName;
  15. default:
  16. return null;
  17. }
  18. }
  19. public int getPropertyCount() {
  20. // TODO Auto-generated method stub
  21. return 2;
  22. }
  23. public void getPropertyInfo(int index, Hashtable ht, PropertyInfo info) {
  24. // TODO Auto-generated method stub
  25. info.namespace=super.NAMESPACE;//这个很重要
  26. switch (index) {
  27. case 0:
  28. info.type=PropertyInfo.STRING_CLASS;
  29. info.name="UId";
  30. break;
  31. case 1:
  32. info.type=PropertyInfo.STRING_CLASS;
  33. info.name="UName";
  34. break;
  35. default:
  36. break;
  37. }
  38. }
  39. public void setProperty(int index, Object value) {
  40. // TODO Auto-generated method stub
  41. switch (index) {
  42. case 0:
  43. UId=value.toString();
  44. break;
  45. case 1:
  46. UName=value.toString();
  47. break;
  48. default:
  49. break;
  50. }
  51. }
  52. public String getUId() {
  53. return UId;
  54. }
  55. public void setUId(String uId) {
  56. UId = uId;
  57. }
  58. public String getUName() {
  59. return UName;
  60. }
  61. public void setUName(String uName) {
  62. UName = uName;
  63. }
  64. }

因为要序列化啊什么什么的,解释起来比较烦。这边也不解释了。大家有兴趣可以去查一下。只说明一下是通过info.namespace+info.name来反序列化的。

3.如果有证书加密,会一直说timeout。

解决方法是在android客户端调用下面这个方法。这个方法要在httptransport.call()之前调用

view plaincopy to clipboardprint?

  1. ClientUtil.SetCertification();  //设置证书

类是这么写的:

view plaincopy to clipboardprint?

  1. public class ClientUtil {
  2. //设置证书被信任
  3. public static void SetCertification() {
  4. try {
  5. HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){
  6. @Override
  7. public boolean verify(String hostname,
  8. SSLSession session) {
  9. // TODO Auto-generated method stub
  10. return true;
  11. }});
  12. SSLContext context = SSLContext.getInstance("TLS");
  13. context.init(null, new X509TrustManager[]{new X509TrustManager(){
  14. public void checkClientTrusted(X509Certificate[] chain,
  15. String authType) throws CertificateException {}
  16. public void checkServerTrusted(X509Certificate[] chain,
  17. String authType) throws CertificateException {}
  18. public X509Certificate[] getAcceptedIssuers() {
  19. return new X509Certificate[0];
  20. }}}, new SecureRandom());
  21. HttpsURLConnection.setDefaultSSLSocketFactory(
  22. context.getSocketFactory());
  23. } catch (Exception e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. }

这个信任一切证书。应为自制的证书是不被信任的,所以shakehand的时候一直timeout。

4.wcf设置的自定义帐号密码认证(userNameAuthentication  )

加入这个之后要在soap发送前在head里面加入用户信息。

加入的方法是:

view plaincopy to clipboardprint?

  1. /*
  2. * authenticator 加入密码账号验证
  3. * */
  4. ServiceConnection connection=super.getServiceConnection();
  5. String Login=Base64.encode("cch:cch1".getBytes());
  6. connection.setRequestProperty("Authorization","Basic "+Login);

这个需要重写httptransport的getServiceConnection()方法。

因为在调用httptransport.call()的时候Connection才被初始化,所以在程序外getServiceConnection().setRequestProperty()会报错说nullpoint。

希望对大家有所帮助。

贴一下解析代码:

view plaincopy to clipboardprint?

  1. int resultCount=response.getPropertyCount();
  2. ArrayList<Dy_sdzbh> list=new ArrayList<Dy_sdzbh>();
  3. for (int i = 0; i < resultCount; i++) {
  4. SoapObject item = (SoapObject)response.getProperty(i);
  5. String sdzbh = item.getProperty("Sdzbh").toString();
  6. String sfm = item.getProperty("Sfm").toString();
  7. Dy_sdzbh modelDySdzbh=new Dy_sdzbh();
  8. modelDySdzbh.setSfdzbm(sdzbh);
  9. modelDySdzbh.setSfm(sfm);
  10. list.add(modelDySdzbh);
  11. }
  12. for (int i = 0; i < resultCount; i++) {
  13. java.lang.System.out.println(list.get(i).getSfm());
  14. }

原文地址:https://www.cnblogs.com/Alex80/p/11111896.html

时间: 2024-10-03 14:41:46

Android 调用.Net WCF服务 .的相关文章

VC使用GSOAP(2.8.14)调用C#WCF服务

我在网上找了好多的这方面的文章,真正能够实现出来的几乎没有. 只有我在1年前下载并调试成功的案例.那么GSOAP是比较复杂的实现过程,需要学习的理论知识也比较多,需要深入了解的可以到官网上去下载. 那么调试时借鉴别人的文章是非常有用的,但是一定要看清对方调试工具的版本号. 1.1.1.1         环境 l  VS2012 l  GSOAP 2.8.14 (请使用指定版本) l   WIN7 IIS 1.1.1.2         下载GSOAP程序包  GSOP2.8 1.1.1.3  

Android调用WebService之服务端实现(一)

webserviceandroidservicemyeclipsestring服务器 目录(?)[-] 一构建WebServices 二新建一个WebService客服端进行测试 原创文章,转载请注明出处:http://www.blog.csdn.net/tangcheng_ok 这个简单的WebService服务将用来给Android客户端调用的,我们使用xfire来实现相关功能.WebService不多做介绍,google下一大堆呢,这里只是简单的搭建一个WebService让Android

Silverlight中异步调用WCF服务,传入回调函数

以前学的ASP.NET,调用的都是同步方法,同步方法的好处就是,一步一步走,完成这步才会走下一步.然而,WCF使用的都是异步方法,调用之后不管有没有获得结果就直接往下走,最可恶的是异步函数都是Void类型,得不到返回结果,虽然有Completed的事件处理,但是还是感觉比较束缚,无法与前端交互. 这里就跟大家分享一种传入回调函数的方法,把前台的方法写好,传到后台,让异步方法调用完成时执行.废话不多说了,开始写代码: 首先,要先建一个带网站的sliverlight项目,这里就不细说了,在网站中添加

实现jquery.ajax及原生的XMLHttpRequest调用WCF服务的方法

废话不多说,直接讲解实现步骤 一.首先我们需定义支持WEB HTTP方法调用的WCF服务契约及实现服务契约类(重点关注各attribute),代码如下: //IAddService.cs namespace WcfService1 { [ServiceContract] public interface IAddService { [OperationContract] [WebInvoke(Method="POST",RequestFormat=WebMessageFormat.Js

三十、【C#.Net开发框架】WCFHosting服务主机的利用WCF服务通讯和实现思路

回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://pan.baidu.com/s/1eQCc69G        前言:以前的系统都是直接客户端直连数据库服务器,后来考虑到服务器的安全性.数据库连接数的限制.分布能力差等问题,特别是那几年中间件.SOA.ESB等炒得比较火,为了跟上时代脚本有必要开发一个中间件,把后台逻辑业务在中间件中运行.刚开始考虑过WebS

WCF服务二:创建一个简单的WCF服务程序

在本例中,我们将实现一个简单的计算服务,提供基本的加.减.乘.除运算,通过客户端和服务端运行在同一台机器上的不同进程实现. 一.新建WCF服务 1.新建一个空白解决方案,解决方案名称为"WCFSolution". 2.解决方案右键->添加->类库项目,类库名称为CalculateWcfService. 3.创建服务契约 WCF采用基于契约的交互方式实现了服务的自制.服务契约:是相关操作的集合.契约就是双方或多方就某个关注点达成的一种共识,是一方向另一方的一种承诺.签署了某个

使用svctraceviewer查看WCF服务异常信息

这两天遇到一个问题,调用一个WCF服务的时候,服务器端正常的返回了数据,但是客户端却遇到了一场 System.ServiceModel.CommunicationException: The underlying connection was closed: The connection was closed unexpectedly. 直接调试查看堆栈信息也没有弄清楚怎么回事.最后上网搜了一下,发现一个获取WCF运行信息的工具. 1.打开服务器端wcf服务的web.config配置文件并添加如

Android调用WebService之客户端实现(二)

原创文章,转载请注明出处:http://www.blog.csdn.net/tangcheng_ok 要在Android调用WebService,必须需要一些库来支持,上面的例子中是,我们通过XFire来访问WebService,但这些库对于我们Android客户端就不适合了.这里介绍一个google code上的一个开源项目Ksoap2-android,Ksoap2-android提供了一个轻量而高效的SOAP库访问WebService. 下载ksoap2-android-assembly-2

WCF初探-14:WCF服务协定

前言: 在前面的文章中,我们定义的服务协定上都会有一个ServiceContract的特性来修饰,这是因为服务契约的实现要靠ServiceContractAttribute 属性定义,然后使用一个或多个类(或接口)方法中的 OperationContractAttribute 属性定义协定的服务操作. 实现服务协定后并将其与WCF 绑定和 EndpointAddress 对象一起使用时,此服务协定将公开以供客户端使用. 公开的信息由 ServiceContractAttribute 表示,其接口