现在大部分应用程序都把业务逻辑处理,数据调用等功能封装成了服务的形式,应用程序只需要调用这些web服务就好了,在这里就不赘述web服务的优点了。本文总结如何在android中调用Web服务,通过传递基类型和复杂类型对比调用.NET平台发布的WCF服务和WebService服务之间的区别。

0 写在前面

以前都是在.NET平台上conding,使用.NET平台发布服务,然后再在.NET的客户端进行调用,非常的方便,最简单的方式就是添加web服务引用,通过添加web服务引用实现像本地调用那样调用web服务,当然我们也可以采用http-post、http-get和基于soap协议的方式去调用服务。

最近在弄andriod的程序,需要调用web服务器上的数据,服务采用C#写的,并部署在iis服务器上。我们可以像.NET那样调用服务那,利用andriod库自带的HttpPost和HttpGet类来调用Web服务。但是wcf服务发布的一些没有添加WebGet或者WebInvoke特性的服务,都只提供基于Soap协议的服务调用方式。虽然soap协议也是基于Http协议,也可以使用HttpPost类来进行调用,但拼凑soap结构体是比较麻烦,好在Ksoap2包提供了调用web服务的方法,而且还比较好的兼容了.NET平台发布的服务。因此本文总结在Andriod中如何使用Ksoap2来调用.NET平台的服务,通过传递基类型和复杂类型对比调用.NET服务发布的WCF服务和WebService服务之间的区别。本文的末尾提供Ksoap2包的下载。

1 WCF服务

我们在服务中提供两个方法,一个计算整数加法,另一个接受People对象并且返回People信息(string)。

1.1 People的数据契约

  1. [DataContract]
  2. public class People
  3. {
  4. [DataMember]
  5. public int Age;
  6. [DataMember]
  7. public string Name;
  8. }

2.2 WCF服务契约

  1. [ServiceContract(Name = "JuameService", Namespace = "http://www.juame.edu")]
  2. public interface ITest
  3. {
  4. [OperationContract]
  5. int Add(int op1, int op2);
  6. [OperationContract]
  7. string PostPeopleInfo(People people);
  8. }

上面的服务契约设置了Namespace特性,该特性重要。在后面的wb服务调用中需要用到。

2.3 WCF服务实现

  1. public class TestService : ITest
  2. {
  3. public int Add(int op1, int op2)
  4. {
  5. return op1 + op2;
  6. }
  7. public string PostPeopleInfo(People people)
  8. {
  9. return "姓名:"+people.Name+"/"+"年龄"+people.Age;
  10. }
  11. }

我们需要把服务部署到IIS中去,因此需要添加一个svc文件,把服务实现的代码写在svc文件中,发布后,服务调用的地址就是svc文件的地址。

2.4 服务配置

  1. <configuration>
  2. <system.web>
  3. <compilation debug="true" targetFramework="4.0" />
  4. </system.web>
  5. <system.serviceModel>
  6. <behaviors>
  7. <serviceBehaviors>
  8. <behavior>
  9. <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->
  10. <serviceMetadata httpGetEnabled="true"/>
  11. <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
  12. <serviceDebug includeExceptionDetailInFaults="false"/>
  13. </behavior>
  14. </serviceBehaviors>
  15. </behaviors>
  16. <services>
  17. <service name="Juame.Service.TestService">
  18. <endpoint address=""
  19. binding="basicHttpBinding"
  20. contract ="Juame.Service.ITest">
  21. </endpoint>
  22. </service>
  23. </services>
  24. <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  25. </system.serviceModel>
  26. <system.webServer>
  27. <modules runAllManagedModulesForAllRequests="true"/>
  28. <!--
  29. 若要在调试过程中浏览 Web 应用程序根目录,请将下面的值设置为 True。
  30. 在部署之前将该值设置为 False 可避免泄露 Web 应用程序文件夹信息。
  31. -->
  32. <directoryBrowse enabled="true"/>
  33. </system.webServer>
  34. </configuration>

主要是配置好Service节点和serviceBehaviors就行,服务采用BasicHttpBinding类型。在这里多提一点。BasicHttpBinding是针对于Soap Web Service协议,而webHttpBinding支持web service协议,因此在wcf服务上加上WebGet或WebInvoke特性的必须要使用webHttpBinding类型。

在iis中发布web服务非常简单和部署asp.net网站一样,服务发布成功之后,能访问到svc的地址。

我们提供的服务,一个是传递基类型(string,int,float等),另外一个是传递对象(复杂类型)。

2 Android调用WCF服务

2.1 android布局

界面布局非常简单,两个Button,一个TextView,按钮分别用来调用两个服务,而TextView用来显示服务调用的结果。

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical"
  6. tools:context="com.example.soapprousage.MainActivity" >
  7. <Button android:id="@+id/btn_jlx"
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content"
  10. android:text="基类型调用"/>
  11. <Button android:id="@+id/btn_obj"
  12. android:layout_width="match_parent"
  13. android:layout_height="wrap_content"
  14. android:text="对象调用"/>
  15. <TextView android:id="@+id/lbl_result"
  16. android:layout_width="match_parent"
  17. android:layout_height="match_parent"
  18. android:textAlignment="viewStart"/>"
  19. </LinearLayout>

2.2 利用Ksoap2调用wcf服务

首先把下载下来的Jar格式的Ksoap包复制到libs(自己创建)文件夹下。

声明服务调用需要的地址和方法

  1. private String nameSpace="http://www.juame.edu";//和wcf服务契约特性的Namespace是一样的
  2. private String url="http://172.21.212.54:8888/TestService.svc";//svc服务地址
  3. private String soapAction="http://www.juame.edu/JuameService/Add";//操作地址
  4. private String methodName="Add";//方法名称

上面声明的服务地址、命名空间、操作地址和方法名称都可以从服务的wsdl文档中查看,

下面利用ksoap2对服务进行调用的代码如下。

  1. protected SoapObject getSoapResult(int op1,int op2){
  2. SoapObject outObject=new SoapObject(nameSpace,methodName);
  3. //添加输出参数
  4. outObject.addProperty("op1", op1);
  5. outObject.addProperty("op2",op2);
  6. SoapSerializationEnvelope serializationEnvelope=new SoapSerializationEnvelope(SoapEnvelope.VER11);//设置soap版本
  7. serializationEnvelope.bodyOut=outObject;
  8. serializationEnvelope.dotNet=true;//调用.NET的服务
  9. HttpTransportSE transportSE=new HttpTransportSE(url);
  10. transportSE.debug=true;//采用调试
  11. try{
  12. transportSE.call(soapAction, serializationEnvelope);//调用服务
  13. SoapObject result=(SoapObject)serializationEnvelope.bodyIn;//获取调用结果
  14. Log.v("happy1", "服务调用成功");
  15. //把结果封送到消息中去,让ui线程显示
  16. Bundle bundle=new Bundle();
  17. bundle.putString("result", result.getProperty(0).toString());//获取结果中的值
  18. Message message=new Message();
  19. message.setData(bundle);
  20. message.what=12;
  21. hander.sendMessage(message);
  22. return result;
  23. }catch(IOException ex){
  24. Log.v("sad", "IO异常");
  25. ex.printStackTrace();
  26. }catch(XmlPullParserException ex){
  27. Log.v("sad", "xml解析异常");
  28. ex.printStackTrace();
  29. }catch(Exception ex){
  30. Log.v("sad", "服务调用异常异常");
  31. }
  32. return null;
  33. }

按钮事件代码,采用多线程。在android3.0后,有关网络资源的调用代码都不能直接在主UI线程中调用,否则会出现android.os.NetworkOnMainThreadException异常。关于android中的多线程机制有时间再进行总结。

  1. //绑定按钮事件
  2. btnJlx.setOnClickListener(new OnClickListener() {
  3. @Override
  4. public void onClick(View arg0) {
  5. // TODO Auto-generated method stub
  6. Thread thread=new Thread(getSoapRequest);
  7. thread.start();
  8. }
  9. });
  10. //线程
  11. Runnable getSoapRequest=new Runnable() {
  12. @Override
  13. public void run() {
  14. // TODO Auto-generated method stub
  15. getSoapResult(10, 20);
  16. }
  17. };
  18. //消息处理
  19. Handler hander = new Handler() {
  20. @Override
  21. public void handleMessage(Message msg) {
  22. if(msg.what=12){
  23. lblResult.append(msg.getData().getString("result")+"\r\n");
  24. }
  25. }
  26. };

到目前为止,我们已经调用了wcf服务第一个服务,就说明传递基类型是没有问题。但是很遗憾的是,对于传递复杂类型和数组集合参数进行调用,在服务那边总是提示无法对传递进来的数据进行反序列化的错误(希望高手指点)。还好我们可以把所以的服务类型都转为json数据,通过json数据进行传递调用,就可以解决复杂类型传递的问题。

对于有强迫症的我来说,不甘心,因为在网上看了许多的教程,利用Ksoap2是可以直接传递复杂类型的来调用.NET平台的服务的。不过网上大部分教程调用的都是传统的webservice服务(asmx文件),于是我就在wcf服务项目中新建一个传统的asmx文件,提供的服务与wcf服务一样的。结果发现,果然能够利用ksoap2传递一个复杂类型来调用服务。下一节总结利用ksoap2传递复杂对象来调用传统的webservice服务。

3 传统的WebService服务

为了和wcf服务进行对比,webservice提供的服务和wcf一致,代码如下:

  1. [WebService(Namespace = "http://tempuri.org/")]
  2. [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  3. [System.ComponentModel.ToolboxItem(false)]
  4. // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
  5. // [System.Web.Script.Services.ScriptService]
  6. public class WebService : System.Web.Services.WebService
  7. {
  8. [WebMethod]
  9. public int Add(int op1, int op2)
  10. {
  11. return op1 + op2;
  12. }
  13. [WebMethod]
  14. public string PostPeopleInfo(People people)
  15. {
  16. return "姓名:" + people.Name + "/" + "年龄:" + people.Age;
  17. }
  18. }

其中WebService特性中的Namespace属性和wcf的Namespace的作用一样的。

同样的也在iis中进行发布。发布成功之后,能够访问到asmx文件。

4 Android调用WebService服务

不管是调用WCF的服务还是WebService的服务,传递基类型去调用,代码都是一样的,且能够正确的调用。下面利用复杂的People类型来调用WebService的服务。

我们需要传递复杂类型,首先我们要在android中建立一个复杂类型,并且复杂类型包含字段名称和个数一定要与服务上的复杂类型保持一致,对于服务的复杂类型具有哪些字段,我们可以通过查看服务调用的示例得知。如下图所示。

根据上面复杂类型的字段说明,我们在android中建立复杂类型(类型名可以随意),包含两个字段且字段名称必须是Age和Name,数据类型也要一致,上面的这个people代表该复杂类型形参名为people(服务调用的时候必须要保持一样)。需要注意的是,这个复杂类型必须要继承KvmSerializable,这样ksoap2进行服务调用的时候,能够把people对象序列化为服务端能够接受的格式。代码如下:

  1. public class People implements KvmSerializable {
  2. public int Age;
  3. public String Name;
  4. @Override
  5. public Object getProperty(int arg0) {
  6. switch (arg0){
  7. case 0:
  8. return Age;
  9. case 1:
  10. return Name;
  11. default:
  12. return null;
  13. }
  14. }
  15. @Override
  16. public int getPropertyCount() {
  17. return 2;
  18. }
  19. @Override
  20. public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2) {
  21. switch (arg0){
  22. case 0:{
  23. arg2.type = PropertyInfo.INTEGER_CLASS;
  24. arg2.name = "Age";
  25. break;
  26. }
  27. case 1:{
  28. arg2.type = PropertyInfo.STRING_CLASS;
  29. arg2.name = "Name";
  30. break;
  31. }
  32. }
  33. }
  34. @Override
  35. public void setProperty(int arg0, Object arg1) {
  36. switch (arg0){
  37. case 0:{
  38. Age = Integer.parseInt(arg1.toString()) ;
  39. break;
  40. }
  41. case 1:{
  42. Name = arg1.toString();
  43. break;
  44. }
  45. }
  46. }
  47. }

下面是传递复杂对象调用web服务,其中服务地址、操作地址、方法名以及命名空间和前面一样,只需要在服务说明wsdl文档中找operation name节点和operation soapAction节点的值即可,其他地方也类似,只是在封装soapobject的时候有一些区别,代码如下:

  1. //地址声明
  2. private String nameSpace="http://tempuri.org/";
  3. private String url="http://172.21.212.54:8888/WebService.asmx";
  4. private String soapAction="http://tempuri.org/PostPeopleInfo";
  5. private String methodName="PostPeopleInfo";
  6. //服务调用
  7. protected SoapObject getSoapResult() {
  8. SoapObject outObject = new SoapObject(nameSpace, methodName);
  9. People people = new People();
  10. // 设置字段值
  11. people.setProperty(0, 23);
  12. people.setProperty(1, "Juame");
  13. // 设置SoapObject对象
  14. outObject.addProperty("people", people);
  15. //也可以这样设置SoapObject
  16. /*PropertyInfo peoInfo = new PropertyInfo();
  17. peoInfo.setName("people");
  18. peoInfo.setValue(people);
  19. peoInfo.setType(People.class);
  20. outObject.addProperty(peoInfo);*/
  21. SoapSerializationEnvelope serializationEnvelope = new SoapSerializationEnvelope(
  22. SoapEnvelope.VER11);//设置soap版本
  23. // 这一步添加映射非常关键
  24. // 第一个参数为命名空间,第二参数为服务器中复杂类型的名称,第三参数是安卓的复杂类型
  25. serializationEnvelope.addMapping(nameSpace, "People", People.class);
  26. serializationEnvelope.bodyOut = outObject;
  27. serializationEnvelope.dotNet = true;// 调用.NET的服务
  28. HttpTransportSE transportSE = new HttpTransportSE(url);
  29. transportSE.debug = true;// 采用调试
  30. try {
  31. transportSE.call(soapAction, serializationEnvelope);// 调用服务
  32. Log.v("happy1", "服务调用成功");
  33. SoapObject result = (SoapObject) serializationEnvelope.bodyIn;
  34. //把结果封送到消息中去,让ui线程显示
  35. Bundle bundle = new Bundle();
  36. bundle.putString("result",result.getProperty(0).toString());
  37. Message message = new Message();
  38. message.setData(bundle);
  39. message.what = 11;
  40. hander.sendMessage(message);
  41. return result;
  42. } catch (IOException ex) {
  43. Log.v("sad", "IO异常");
  44. ex.printStackTrace();
  45. } catch (XmlPullParserException ex) {
  46. Log.v("sad", "xml解析异常");
  47. ex.printStackTrace();
  48. } catch (Exception ex) {
  49. Log.v("sad", "服务调用异常异常");
  50. }
  51. return null;
  52. }
  53. //按钮事件
  54. btnObj.setOnClickListener(new OnClickListener() {
  55. @Override
  56. public void onClick(View arg0) {
  57. // TODO Auto-generated method stub
  58. Thread thread = new Thread(getSoapRequest);
  59. thread.start();
  60. }
  61. });
  62. //线程
  63. Runnable getSoapRequest=new Runnable() {
  64. @Override
  65. public void run() {
  66. // TODO Auto-generated method stub
  67. getSoapResult();
  68. }
  69. };
  70. //消息处理
  71. Handler hander = new Handler() {
  72. @Override
  73. public void handleMessage(Message msg) {
  74. if(msg.what=11){
  75. lblResult.append(msg.getData().getString("result")+"\r\n");
  76. }
  77. }
  78. };

上面的代码就能够传递复杂类型去调用WebService的服务,返回结果如下:

  1. 姓名:Juame/年龄:23

5 简述Wcf与WebServic的区别

WebService是一个行业标准,也是Web Service的规范,既不是框架,也不是技术,它使用xml扩展标记语言来表示数据,这正是WebService能够跨语言和平台的关键,而微软的Web服务实现称为ASP.NET Web Service.它使用Soap简单对象访问协议来实现分布式环境里应用程序之间的数据交互。

WCF 是一个分布式应用的开发框架,属于特定的技术,或者平台。既不是标准也不是规范。在一定程度上就是WebService,不得不说WCF确实非常方便,提供非常多且好用的特性,可以用来创建各种服务,而且自定义性也高,以后项目的服务搭建都会基于WCF来实现。

6 小结

本文总结了如何使用android调用web服务。在传递复杂类型调用服务的时候纠结的了半天,最后实现了传递复杂类型调用WebService服务,但没有实现对WCF服务的调用,而传递基类型调用服务,两者都可以。在第5小节中还简述了wcf和webservice之间的区别,其实在项目大都是采用wcf框架来发布自己的服务。下面会继续总结如何用javascript来调用wcf发布的服务。

另Ksaop2下载链接:http://download.csdn.net/download/mingge38/9666650

Android调用Web服务的更多相关文章

  1. 动态调用web服务

    通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务.这样是使工作简单了,但是却和提供Web服务的URL.方法名 ...

  2. 使用ASP.NET AJAX 从脚本中调用Web 服务的应用方法

    技能点:通过编写WebService,在页面js中调用WebService来进行数据查询. 网站开发,有些时候需要使用js在页面动态生成一些内容,但还有些数据要通过查询数据库才能获取的. 但由于诸如主 ...

  3. 在 SQL Server 的存储过程中调用 Web 服务

    介绍 一个老朋友计划开发一个应用,基于 .NET 和 Socket,但需要在存储过程中调用 Web 服务. 在这篇文章中我们将分享这个应用的经验,讲述如何在存储过程中调用 Web 服务,并传递参数. ...

  4. mvc路由引起异步调用web服务的问题

    从一篇blog得知使用脚本可以异步调用Web服务,觉得很新鲜,因为自己很少用到Web服务,所以决定写一写看看什么效果. 首先在UI项目(我使用的是MVC4.0)里创建一个Web服务. 添加Web服务后 ...

  5. 动态调用web服务 --WSHelper.cs

    using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Net;us ...

  6. 25.C# 异步调用Web服务

    1.创建Web服务 1.1VS新建ASP.Net空Web应用程序 1.2添加Web服务新建项 1.3添加GetWeather方法和相关类 using System; using System.Coll ...

  7. Xamarin.Android 调用Web Api(通过ListView展示远程获取的数据)

    xamarin.android如何调用sqlserver 数据库呢(或者其他的),很多新手都会有这个疑问.xamarin.android调用远程数据主要有两种方式: 在Android中保存数据或调用数 ...

  8. 采用动态代理方式调用WEB服务(转载+整理)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. [置顶] Xamarin android 调用Web Api(ListView使用远程数据)

    xamarin android如何调用sqlserver 数据库呢(或者其他的),很多新手都会有这个疑问.xamarin android调用远程数据主要有两种方式: 在Android中保存数据或调用数 ...

随机推荐

  1. css知识

    margin和padding是什么意思 margin外边距,padding内边距,外边距表示一个元素的边到相邻元素的距离,内边距表示元素之间的内容和元素边框的距离. font:12px/1.5 表示什 ...

  2. IntelliJ IDEA 的SVN配置与使用

    SVN 首先提一句,IDEA对各种的版本控制工具的支持是非常好的,点击3 打开系统设置界面,就可以看到他有专门的一栏 Version Control 里边是对各种版本控制工具的支持,其中我要用的SVN ...

  3. linq之where子句

    在Linq中,where子句主要是来指定筛选元素的逻辑条件.linq查询中where子句不是必须的,可以不包括where子句,也可以包含多个where子句,where子句中可以包含一个或多个bool类 ...

  4. [CLR via C#]18. Attribute

    attribute可以说是Microsoft .NET Framework提出的最具创意的技术之一了.利用attribute,可以声明性的为自己的代码构造添加注解,从而实现一些特殊的功能.attrib ...

  5. C# 进制转换参考

    //十进制转二进制 Console.WriteLine(Convert.ToString(69, 2)); //十进制转八进制 Console.WriteLine(Convert.ToString(6 ...

  6. csharp:Chart

    http://www.dotnetperls.com/chart using System; using System.Windows.Forms; using System.Windows.Form ...

  7. PHPWind 8.7中插件金币竞价插件的漏洞

    尽管pw团队解散,但无数站点仍在运行. 该插件的名字叫jbjingpai 无意中看到这样一篇帖子,说有漏洞 http://www.phpwind.net/read/1716722 ,不是空穴来风,查一 ...

  8. kfreebsd不适用于实际环境

    debian搞的kfreebsd,其中有很多常用的软件包处于依赖破损的状态,个人觉得是无法用作日常开发或生产环境的. 当然,对于只使用其中几项完整可用功能的场景,基本上还是可以的. 当时看个这个东东的 ...

  9. JPA学习(6)JPQL

    JPQL语言,即 Java Persistence Query Language 的简称.JPQL 是一种和 SQL 非常类似的中间性和对象化查询语言,它最终会被编译成针对不同底层数据库的 SQL 查 ...

  10. CentOS7 Debian 8 安装VMware-tools

    如在安装过程中碰到未找到gcc 或者 kernel headers的可按以下方案解决,适用任意版本 CentOS 7 1. Update the kernel: $ yum update kernel ...