本来以为在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.调用是参数的说明

  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不对应的原因。下面是一个例子

服务端代码:

  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类:

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

android客户端代码如下:

  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:

  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类

  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()之前调用

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

类是这么写的:

  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里面加入用户信息。

加入的方法是:

  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。

希望对大家有所帮助。

贴一下解析代码:

  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. }

3 SoapObject 解析
          SoapObject  soapChild=(SoapObject)result.getProperty(int);

For(int i=0; i<soapChild.getPropertyCount();i++){

SoapObject  soapChilds=(SoapObject)result.getProperty(i);

String data=soapChilds.getProperty(“Key_Name”).toString();

}

SoapObject类是一个主要用于调用WCF服务的类,其对象可以作为请求,发送到WCF服务器;也可以用于存储响应信息。

该对象本身是一个存储了一套HTML语句的文本。而SoapObject本身提供了对这套HTML语句的解析。

我们对SoapObject的解析,其实可以理解为对HTML语句的解析。

本文以String类型为获取目标(即从WCF服务器提供方法返回的是String类型的数据)

首先我们把返回的String类型分成三种情况:单一个String, 一个String的数组,一个String的二维数组

①对于单一个String,我们在编写调用WCF服务的方法的时候,envelope.bodyIn就不能强制转换成SoapObject,否则会在运行时提示类型转换错误。此时envelope.bodyIn可以直接作为一个Object对象返回,也可以调用其toString()方法,即可获得想要的数据。

②对于一个String的一维数组,我们要把envelope.bodyIn强制转换成SoapObject,获取一个SoapObject类型的对象soap。

此时,只要调用SoapObject的getProperty()方法即可获得想要的数据,参数对应一维数组下标。

例如:要从返回一维数组获取第一个元素,只要调用soap.setProperty(0)即可。

③对于一个String的二维数组。

此时。通过调试发现,getProgerty()方法返回的是另一个SoapObject对象,因此我们可以把envelope.bodyIn的SoapObject对象想象成一个二维数组,其中getProperty()方法是返回一维数组的某一行,参数是对应行下标,再通过调用这一个SoapObject的getProperty()方法,即可获取某一元素。

例如:要获取String[0][1]元素,只要从envelope.bodyIn的SoapObject调用两次getProperty()方法:soap.getProperty(0).getProperty(1)

可见,只要把SoapObject抽象成一个数组,就不难去理解和解析其中的数据。

把SoapObject想象成一个数组,这个数组当中的元素可以是他自己,soapObject.setProperty(int index, Object value),此处的value也可以是一个soapObject对象

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

  1. Android调用Web服务

    现在大部分应用程序都把业务逻辑处理,数据调用等功能封装成了服务的形式,应用程序只需要调用这些web服务就好了,在这里就不赘述web服务的优点了.本文总结如何在android中调用Web服务,通过传递基 ...

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

    以前学的ASP.NET,调用的都是同步方法,同步方法的好处就是,一步一步走,完成这步才会走下一步.然而,WCF使用的都是异步方法,调用之后不管有没有获得结果就直接往下走,最可恶的是异步函数都是Void ...

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

    废话不多说,直接讲解实现步骤 一.首先我们需定义支持WEB HTTP方法调用的WCF服务契约及实现服务契约类(重点关注各attribute),代码如下: //IAddService.cs namesp ...

  4. SharePoint 2013 调用WCF服务简单示例

    内容比较简单,主要记录自己使用SharePoint 2013WCF服务遇到的小问题和小经验,分享给大家,希望能够给需要的人有所帮助.好吧,进入正题! 第一部分 SharePoint 2013调用自带W ...

  5. VS2010中使用Jquery调用Wcf服务读取数据库记录

    VS2010中使用Jquery调用Wcf服务读取数据库记录 开发环境:Window Servere 2008 +SQL SERVE 2008 R2+ IIS7 +VS2010+Jquery1.3.2 ...

  6. Wcf for wp8 创建wcf服务 连接wp8模拟器并显示来自wcf服务的接口信息 (一)

    下载: vs2012 pro for wp8 iis express http://download.microsoft.com/download/B/2/8/B2801FEE-9A60-4AFA-8 ...

  7. WCF学习之旅—WCF服务部署到IIS7.5(九)

    上接   WCF学习之旅—WCF寄宿前的准备(八) 四.WCF服务部署到IIS7.5 我们把WCF寄宿在IIS之上,在IIS中宿主一个服务的主要优点是在发生客户端请求时宿主进程会被自动启动,并且你可以 ...

  8. WCF学习之旅—WCF服务配置(十四)

    一.概述 我们在前面章节中讲了寄宿,在前面的实例中也用到了配置文件,这一篇主要讲讲如何在应用配置文件,提高WCF程序的灵活性.在编写WCF服务应用程序时,编写配置项也是其中一项主要工作,在前面的几个示 ...

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

    在本例中,我们将实现一个简单的计算服务,提供基本的加.减.乘.除运算,通过客户端和服务端运行在同一台机器上的不同进程实现. 一.新建WCF服务 1.新建一个空白解决方案,解决方案名称为"WC ...

随机推荐

  1. openwrt配置strongswan对接hillstone ipsec的笔记

    一.主要参考资料: https://openwrt.org/docs/guide-user/services/vpn/ipsec/strongswan/roadwarrior https://open ...

  2. 运维开发笔记整理-URL配置

    运维开发笔记整理-URL配置 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.URL路由 对于高质量的Web应用来说,使用简洁,优雅的URL的路由是一个非常值得重视的细节.Dja ...

  3. 关于Istio 1.1,你所不知道的细节

    本文整理自Istio社区成员Star在 Cloud Native Days China 2019 北京站的现场分享 第1则 主角 Istio Istio作为service mesh领域的明星项目,从2 ...

  4. VMware Linux系统克隆

    系统克隆 网卡设备无法识别 解决克隆虚拟机后网卡设备无法识别启动问题的方法 一.故障问题 从vmware workstation中克隆(clone)了一个CentOS 6的虚拟机,启动之后发现网卡没有 ...

  5. Java精通并发-透过字节码理解synchronized关键字

    在上一次https://www.cnblogs.com/webor2006/p/11428408.html中对于synchronized关键字的作用做了一个实例详解,下面再来看一下这个程序: 请问下, ...

  6. 0023SpringMVC自定义类型转换器

    页面录入的字符串:2019/12/05可以映射到实体的日期属性上,但是如果是录入2019-12-05就会报错400 bad request,想要以2019-12-05日期格式的方式映射到实体的日期属性 ...

  7. jemeter 查看结果树 分析

    查看结果树,可以看到测试通过,通过 的测试通常为绿色.红色则代表失败了.可以查看到取样器结果,请求,响应数据 取样器结果中可以查看到响应头,响应数据大小,响应时间等信息. Thread Name: 线 ...

  8. vscode——配置go插件

    前言 这个真的折腾死我了,看了N多博客才弄好 这两个还是比较有用的~ https://www.cnblogs.com/nickchou/p/9038114.html https://www.jians ...

  9. linux第三天

    一.用户的类型   1.root管理员:所有权限(r w x)   2.文件拥有者(u):谁创建谁拥有   3.组 (g):用户组   4.其它用户(o):不属于用户组,也不是文件的创建者,不是管理员 ...

  10. Enterprise Architect 14破解版 安装包 安装教程

    安装包以及破解补丁下载: 链接:https://pan.baidu.com/s/1es0wN_6-d9pk4xnSN1SiFA 提取码:bor0 安装包链接失效可在下方留言 安装以及破解教程 参考链接 ...