首页 > 代码库 > IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,

IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,

最近做一个项目后端使用WCF接收Android手机拍照并带其它参数保存到服务器里;刚好把最近学习的WCF利用上,本以为是个比较简单的功能应该很好实现,没想到其中碰到不少问题,在网上搜索很久一直没有想到的解决方案,最后实现对数据流的分段写入然后后端再来解析流实现的此功能;后端运用WCF中的REST来接收数据;REST还是比较简单的知识,若是不懂可以简单网上了解一下;下面我们先了解一些本次运用到的理论知识:

 

一:理论知识

由于低层协议特性限制,WCF的流模式只支持如下四种:1:BasicHttpBinding 2:NetTcpBinding 3:NetNamedPipeBinding 4:WebHttpBinding

1.设置TransferMode。它支持四种模式(Buffered、Streamed、StreamedRequest、StreamedResponse),请根据具体情况设置成三种Stream模式之一。

2.修改MaxReceivedMessageSize。该值默认大小为64k,因此,当传输数据大于64k时,则抛出CommunicationException异常。  

3.修改receiveTimeout 和sendTimeout。大数据传送时间较长,需要修改这两个值,以免传输超时。

 

二:解决问题

WCF如果使用Stream做为参数时只能唯一一个,不能有其它另外的参数,这个也是本次碰到要重点解决的一个问题;可是我们Android手机除的图片还要有其它的参数,最后决定采用手机端把参数跟图片都一起写入Stream里面,后端WCF再来解析这个参数的流;

下面就是定义好Stream的格式,传过来的Stream分成三部分: 参数信息长度  参数信息   图片

1 参数信息长度(1字节):用于存放参数信息的长度(以字节为单位);

2 参数信息: 除图片以外的参数,以JSON的形式存放如{"type":"jpg","EmployeeID":"12","TaskID":"13"}

3 图片:图片的字节

 

三:WCF编码内容

1:我们首先定义一个WCF契约,由于我们运用REST(在命名空间ServiceModel.Web下面)契约IAndroidInfo内容如下,采用POST方式进行接收:

using System.ServiceModel;using System.Runtime.Serialization;using System.ServiceModel.Web;using System.IO;namespace Coreius.CEIMS.AndroidInterface{    [ServiceContract]    public interface IAndroidInfo    {         [WebInvoke(UriTemplate = "GpsUpFile", Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]        bool GpsUpFile(Stream ImageContext);    }}

 

2:根据契约我们定义服务的内容,接收一个流的参数内容,首先把这个Stream转化成字节,然后根据我们先前约定好的内容获得第一个字节的值,再根据此值定义我们另外三个参数的字节长度,再通过JSON转换格式把它里面的三个参数值取出来,最后其它字节是存放一张手机拍的照片,把它存放在于们服务器D盘文件夹下

using System.Linq;using System.Text;using System.ServiceModel;using System.ServiceModel.Web;using System.IO;using Newtonsoft.Json;namespace Coreius.CEIMS.AndroidService{    public class AndroidInfoService:IAndroidInfo    {      public bool GpsUpFile(Stream ImageContext)        {            byte[] m_Bytes = ReadToEnd(ImageContext);            int len = (int)m_Bytes[0];            byte[] data = http://www.mamicode.com/m_Bytes.Skip(1).Take(len).ToArray();"d:";            string FileAddress = "\\UpLoad\\";            string LocationAddress = DiskName + FileAddress;            if (!DirFileHelper.IsExistDirectory(LocationAddress))            {                DirFileHelper.CreateDirectory(LocationAddress);            }            string ImageName = DateTime.Now.ToString("yyyyMMddhhmmss.") + ImageType;            string ImagePath = LocationAddress + ImageName;            if (!File.Exists(ImagePath))            {                try                {                    System.IO.File.WriteAllBytes(ImagePath, Imagedata);                    ImageContext.Close();                    return true;                }                catch                {                    return false;                }            }            else            {                return false;            }        }    }}

上面的代码用到几个方法,比如把流转化成字节、把JSON转化成实现等,代码如下:

public byte[] ReadToEnd(System.IO.Stream stream)        {            long originalPosition = 0;            if (stream.CanSeek)            {                originalPosition = stream.Position;                stream.Position = 0;            }            try            {                byte[] readBuffer = new byte[4096];                int totalBytesRead = 0;                int bytesRead;                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)                {                    totalBytesRead += bytesRead;                    if (totalBytesRead == readBuffer.Length)                    {                        int nextByte = stream.ReadByte();                        if (nextByte != -1)                        {                            byte[] temp = new byte[readBuffer.Length * 2];                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);                            readBuffer = temp;                            totalBytesRead++;                        }                    }                }                byte[] buffer = readBuffer;                if (readBuffer.Length != totalBytesRead)                {                    buffer = new byte[totalBytesRead];                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);                }                return buffer;            }            finally            {                if (stream.CanSeek)                {                    stream.Position = originalPosition;                }            }        }    public class JsonModel    {        public string type { get; set; }        public string EmployeeID { get; set; }        public string TaskID { get; set; }    }

3:新建一个文本,然后修改其后缀名为.svc,作为我们发布服务(宿主为IIS)让Android手机调用, 然后把下面的代码写入

<%@ ServiceHost Language="C#" Debug="true" Service="Coreius.CEIMS.AndroidService.AndroidInfoService" %>

修改Web.config里面的内容:

<?xml version="1.0" encoding="utf-8"?><configuration>  <appSettings>    <add key="ConnectionString" value="http://www.mamicode.com/server=127.0.0.1;database=Coreius;uid=sa;pwd=admin"/>  </appSettings>  <system.web>    <compilation debug="true" targetFramework="4.0" />  </system.web>  <system.serviceModel>    <behaviors>      <endpointBehaviors>        <behavior name="webHttp">          <webHttp helpEnabled="true"/>        </behavior>      </endpointBehaviors>      <serviceBehaviors>        <behavior name="MapConfigBehavior">          <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->          <serviceMetadata httpGetEnabled="true"/>          <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->          <serviceDebug includeExceptionDetailInFaults="true"/>          <dataContractSerializer maxItemsInObjectGraph="2147483647"/>        </behavior>      </serviceBehaviors>    </behaviors>    <bindings>      <webHttpBinding>        <binding name="webHttpBindConfig" receiveTimeout="00:30:00" sendTimeout="00:30:00" maxReceivedMessageSize="104857600" transferMode="Streamed">          <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"/>          <security mode="None"></security>        </binding>      </webHttpBinding>    </bindings>    <services>      <service name="Coreius.CEIMS.AndroidService.AndroidInfoService" behaviorConfiguration="MapConfigBehavior">        <endpoint binding="webHttpBinding" contract="Coreius.CEIMS.AndroidInterface.IAndroidInfo" bindingConfiguration="webHttpBindConfig" behaviorConfiguration="webHttp"/>       </service>    </services>  </system.serviceModel></configuration>

此处有些要注意的地方:

(1):此处采用的是webHttpBinding 所以一定要设置behaviorConfiguration才会有效果,其中helpEnabled="true"则是为实现可以在发布可以查看帮助信息    

        <behavior name="webHttp">          <webHttp helpEnabled="true"/>        </behavior>

(2):为了实现上传大文件所以我们要如下设置最大值,其中security是设置访问服务的认证,此处是把它设置成为不认证,transferMode就是设置运用流的模式

      <webHttpBinding>        <binding name="webHttpBindConfig" receiveTimeout="00:30:00" sendTimeout="00:30:00" maxReceivedMessageSize="104857600" transferMode="Streamed">          <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"/>          <security mode="None"></security>        </binding>      </webHttpBinding>

4:编写完上面的代码后就可以服务器IIS上部署这个WCF服务:

 

四:Android编码

由于Android手机端的代码是另外一个朋友编写,所以就把大体的代码贴出来,大体的原理就是把参数跟图片写入流,然后调用部署好的WCF服务

代码一:因为服务器不是公用的,所以下面的IP我就随便修改的一个;

private void toUploadFile(File file) throws FileNotFoundException {		String result = null;		requestTime= 0;		int res = 0;		long requestTime = System.currentTimeMillis();		long responseTime = 0;				//封装参数信息		JSONObject jsonObject = new JSONObject();		try {			jsonObject.put("EmployeeID", MainActivity.guid);			jsonObject.put("TaskID", "e52df9b4-ee3b-46c5-8387-329b76356641");			String[] type = file.getName().split("\\.");			jsonObject.put("type", type[type.length-1]);		} catch (JSONException e) {			// TODO Auto-generated catch block			e.printStackTrace();		}				/**上传文件*/		HttpParams httpParameters = new BasicHttpParams();	    HttpConnectionParams.setConnectionTimeout(httpParameters, 1000*30);	    HttpConnectionParams.setSoTimeout(httpParameters, 1000*30);	    HttpConnectionParams.setTcpNoDelay(httpParameters, true);					String path = PictureUtil.zipNewImage(file);	//压缩文件后返回的文件路径		byte[] bytes = null;	    InputStream is;	    File myfile = new File(path);		try {			is = new FileInputStream(path);			bytes = new byte[(int) myfile.length()];			int len = 0;			int curLen = 0;			while ((len = is.read(bytes)) != -1) {				curLen += len;				is.read(bytes);			}			is.close();		} catch (FileNotFoundException e1) {			// TODO Auto-generated catch block			e1.printStackTrace();		} catch (IOException e) {			// TODO Auto-generated catch block			e.printStackTrace();		}		byte[] updata = http://www.mamicode.com/GpsImagePackage.getPacket(jsonObject.toString(), bytes);	//参数与文件封装成单个数据包"binary/octet-stream");        reqEntity.setChunked(true);        httpPost.setEntity(reqEntity);        try {			httpResponse = httpClient.execute(httpPost);			responseTime = System.currentTimeMillis();			this.requestTime = (int) ((responseTime-requestTime)/1000);			res = httpResponse.getStatusLine().getStatusCode();			if (httpResponse.getStatusLine().getStatusCode() ==200) {				Log.e(TAG, "request success");				Log.e(TAG, "result : " + result);				return;			} else {				Log.e(TAG, "request error");				sendMessage(UPLOAD_SERVER_ERROR_CODE,"上传失败:code=" + res);				return;			}            } catch (ClientProtocolException e) {				// TODO Auto-generated catch block				e.printStackTrace();			} catch (IOException e) {				// TODO Auto-generated catch block				e.printStackTrace();			}	}package com.anthony.util;/** * 服务器端接口 * @author YWJ * */public class MyUrl {	public static String upload_GPS = "http://122.199.19.23:8088/AndroidInfoService.svc/SetGpsInfo";}

 

代码二:

package com.anthony.util;public class GpsImagePackage {	public GpsImagePackage() {		// TODO Auto-generated constructor stub	}		//封装字节数组与参数	public static byte[] getPacket(String json,byte[] image){				byte[] jsonb = json.getBytes();		int length = image.length + jsonb.length;		System.out.println(image.length +"    "+ jsonb.length);		byte[] bytes = new byte[length+1];		byte[] lengthb = InttoByteArray(jsonb.length, 1);		System.arraycopy(lengthb, 0, bytes, 0, 1);		System.arraycopy(jsonb, 0, bytes, 1, jsonb.length);		System.arraycopy(image, 0, bytes, 1+jsonb.length, image.length);		return bytes;			}		//将int转换为字节数组    public static byte[] InttoByteArray(int iSource, int iArrayLen) {    	    	byte[] bLocalArr = new byte[iArrayLen];    	for ( int i = 0; (i < 4) && (i < iArrayLen); i++) {             bLocalArr[i] = (byte)( iSource>>8*i & 0xFF );        }         return bLocalArr;    }     // 将byte数组bRefArr转为一个整数,字节数组的低位是整型的低字节位     public static int BytestoInt(byte[] bRefArr) {    	     	 int iOutcome = 0;         byte bLoop;         for ( int i =0; i<bRefArr.length ; i++) {            bLoop = bRefArr[i];            iOutcome+= (bLoop & 0xFF) << (8 * i);         }        return iOutcome;     }}

 

五:运行效果:

 

 

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。  因为,我的写作热情也离不开您的肯定支持。