Android 调用.Net WCF服务 .

Android 调用.Net WCF服务 .,第1张

概述本来以为在java平台上用axis2生成了客户端代理类然后移植到Android平台上就好了。没想到在移植过程中出现了很多问题。说明JVM和android的DVM差距还是很大的。 JVM执行的是class文件,而DVM执行的是dex文件。 在eclipse里面开发Android程序的时候在编译时会把jar包里面的class一个个编译成DVM可执行的dex文件。当然,有个前提是jar包是放在sourc

本来以为在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 plain copy to clipboard print ? static String nameSpace="http://tempuri.org/";   static String URL="https://10.0.2.2:9001/test";   static String SOAP_ACTION="http://tempuri.org/ITestService/GetUser";   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 plain copy to clipboard print ? User ITestService.GetUser(User u)           {               User user = new User();               user.UID = "Server:" + u.UID;               user.Uname = "Server:" + u.Uname;               return user;           }  

 

 

User类:

 

view plain copy to clipboard print ? [DataContract]       public class User       {           [DataMember]           public string UID;           [DataMember]           public string Uname;       }  

 

 

 

androID客户端代码如下:

 

view plain copy to clipboard print ? SoapObject requet=new SoapObject(nameSpace,Methodname);                      PropertyInfo perPropertyInfo=new PropertyInfo();           User user=new User();           user.setUID("123");           user.setUname("cch");           perPropertyInfo.setname("u");           perPropertyInfo.setValue(user);           perPropertyInfo.setType(User.class);           requet.addProperty(perPropertyInfo);                      SoapSerializationEnvelope envelope=new SoapSerializationEnvelope(SoapEnvelope.VER11);           envelope.addMapPing(User.nameSPACE,"User",User.class);//register 这个很重要            envelope.setoutputSoapObject(requet);           envelope.dotNet=true;           AndroIDhttpTransport transport=new AndroIDhttpTransport (URL);                      ClIEntUtil.SetCertification();  //设置证书            try {                              transport.call(SOAP_ACTION,envelope);   //                          SoapObject response=(SoapObject)envelope.getResponse();   //                          //PraseXML_SF(response);                ((TextVIEw)findVIEwByID(R.ID.txt01)).setText(String.valueOf(response.toString()));           } catch (IOException e) {               // Todo auto-generated catch block                e.printstacktrace();           } catch (XmlPullParserException e) {               // Todo auto-generated catch block                e.printstacktrace();           }  

 

 

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

先BaSEObject:

 

view plain copy to clipboard print ? package CCH.Model;   import org.ksoap2.serialization.KvmSerializable;   import org.ksoap2.serialization.soapObject;   public abstract class BaSEObject implements KvmSerializable   {       public static final String nameSPACE = "http://schemas.datacontract.org/2004/07/TestService";       //public static final String nameSPACE = "http://schemas.datacontract.org/2004/07/HL7.Base.Struct";            public BaSEObject() {               super();           }          }  

 

 

然后是User类

 

view plain copy to clipboard print ? package CCH.Model;   import java.util.Hashtable;   import org.ksoap2.serialization.PropertyInfo;   public class User extends BaSEObject   {       private String UID;       private String Uname;              public Object getProperty(int index) {           // Todo auto-generated method stub            switch (index) {           case 0:               return UID;           case 1:               return Uname;           default:               return null;           }       }       public int getPropertyCount() {           // Todo auto-generated method stub            return 2;       }       public voID getPropertyInfo(int index, Hashtable ht, PropertyInfo info) {           // Todo auto-generated method stub            info.namespace=super.nameSPACE;//这个很重要            switch (index) {           case 0:               info.type=PropertyInfo.STRING_CLASS;               info.name="UID";               break;           case 1:               info.type=PropertyInfo.STRING_CLASS;               info.name="Uname";               break;           default:               break;           }       }       public voID setProperty(int index, Object value) {           // Todo auto-generated method stub            switch (index) {           case 0:               UID=value.toString();               break;           case 1:               Uname=value.toString();               break;           default:               break;           }       }       public String getUID() {           return UID;       }       public voID setUID(String uID) {           UID = uID;       }       public String getUname() {           return Uname;       }       public voID setUname(String uname) {           Uname = uname;       }          }  

 

 

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

 

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

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

 

 

view plain copy to clipboard print ? ClIEntUtil.SetCertification();  //设置证书  

 

类是这么写的:

 

view plain copy to clipboard print ? public class ClIEntUtil {       //设置证书被信任        public static voID SetCertification() {           try {               httpsURLConnection.setDefaultHostnameVerifIEr(new HostnameVerifIEr(){                       @OverrIDe                       public boolean verify(String hostname,                               SSLSession session) {                           // Todo auto-generated method stub                            return true;                       }});               SSLContext context = SSLContext.getInstance("TLS");               context.init(null, new x509trustmanager[]{new x509trustmanager(){                       public voID checkClIEntTrusted(X509Certificate[] chain,                                       String authType) throws CertificateException {}                       public voID checkServerTrusted(X509Certificate[] chain,                                       String authType) throws CertificateException {}                       public X509Certificate[] getAcceptedissuers() {                               return new X509Certificate[0];                       }}}, new SecureRandom());               httpsURLConnection.setDefaultSSLSocketFactory(                               context.getSocketFactory());       } catch (Exception e) {                e.printstacktrace();       }   }   }  

 

 

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

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

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

加入的方法是:

 

view plain copy to clipboard print ? /*           * authenticator 加入密码账号验证           * */           ServiceConnection connection=super.getServiceConnection();           String Login=Base64.encode("cch:cch1".getBytes());           connection.setRequestProperty("Authorization","Basic "+Login);  

 

 

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

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

 

希望对大家有所帮助。

 

贴一下解析代码:

 

view plain copy to clipboard print ? int resultCount=response.getPropertyCount();           ArrayList<Dy_sdzbh> List=new ArrayList<Dy_sdzbh>();           for (int i = 0; i < resultCount; i++) {               SoapObject item = (SoapObject)response.getProperty(i);               String sdzbh = item.getProperty("Sdzbh").toString();               String sfm = item.getProperty("Sfm").toString();               Dy_sdzbh modelDySdzbh=new Dy_sdzbh();               modelDySdzbh.setSfdzbm(sdzbh);               modelDySdzbh.setSfm(sfm);               List.add(modelDySdzbh);           }           for (int i = 0; i < resultCount; i++) {               java.lang.System.out.println(List.get(i).getSfm());           }  

 

 

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服务 .全部内容,希望文章能够帮你解决Android 调用.Net WCF服务 .所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1129498.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-30
下一篇 2022-05-30

发表评论

登录后才能评论

评论列表(0条)

保存