IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,...
最近做一個項目后端使用WCF接收Android手機拍照并帶其它參數(shù)保存到服務器里;剛好把最近學習的WCF利用上,本以為是個比較簡單的功能應該很好實現(xiàn),沒想到其中碰到不少問題,在網(wǎng)上搜索很久一直沒有想到的解決方案,最后實現(xiàn)對數(shù)據(jù)流的分段寫入然后后端再來解析流實現(xiàn)的此功能;后端運用WCF中的REST來接收數(shù)據(jù);REST還是比較簡單的知識,若是不懂可以簡單網(wǎng)上了解一下;下面我們先了解一些本次運用到的理論知識:
一:理論知識
由于低層協(xié)議特性限制,WCF的流模式只支持如下四種:1:BasicHttpBinding 2:NetTcpBinding 3:NetNamedPipeBinding 4:WebHttpBinding
1.設置TransferMode。它支持四種模式(Buffered、Streamed、StreamedRequest、StreamedResponse),請根據(jù)具體情況設置成三種Stream模式之一。
2.修改MaxReceivedMessageSize。該值默認大小為64k,因此,當傳輸數(shù)據(jù)大于64k時,則拋出CommunicationException異常。 ?
3.修改receiveTimeout 和sendTimeout。大數(shù)據(jù)傳送時間較長,需要修改這兩個值,以免傳輸超時。
二:解決問題
WCF如果使用Stream做為參數(shù)時只能唯一一個,不能有其它另外的參數(shù),這個也是本次碰到要重點解決的一個問題;可是我們Android手機除的圖片還要有其它的參數(shù),最后決定采用手機端把參數(shù)跟圖片都一起寫入Stream里面,后端WCF再來解析這個參數(shù)的流;
下面就是定義好Stream的格式,傳過來的Stream分成三部分: 參數(shù)信息長度??參數(shù)信息?? 圖片
1 參數(shù)信息長度(1字節(jié)):用于存放參數(shù)信息的長度(以字節(jié)為單位);
2 參數(shù)信息: 除圖片以外的參數(shù),以JSON的形式存放如{"type":"jpg","EmployeeID":"12","TaskID":"13"}
3 圖片:圖片的字節(jié)
三:WCF編碼內(nèi)容
1:我們首先定義一個WCF契約,由于我們運用REST(在命名空間ServiceModel.Web下面)契約IAndroidInfo內(nèi)容如下,采用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:根據(jù)契約我們定義服務的內(nèi)容,接收一個流的參數(shù)內(nèi)容,首先把這個Stream轉(zhuǎn)化成字節(jié),然后根據(jù)我們先前約定好的內(nèi)容獲得第一個字節(jié)的值,再根據(jù)此值定義我們另外三個參數(shù)的字節(jié)長度,再通過JSON轉(zhuǎn)換格式把它里面的三個參數(shù)值取出來,最后其它字節(jié)是存放一張手機拍的照片,把它存放在于們服務器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 = m_Bytes.Skip(1).Take(len).ToArray();string Jsonstr = System.Text.Encoding.Default.GetString(data);JsonModel item = JsonConvert.DeserializeObject<JsonModel>(Jsonstr);string ImageType=item.type;string EmployeeID=item.EmployeeID;string TaskID=item.TaskID;byte[] Imagedata = m_Bytes.Skip(1 + len).ToArray();string DiskName = "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;}}} }上面的代碼用到幾個方法,比如把流轉(zhuǎn)化成字節(jié)、把JSON轉(zhuǎn)化成實現(xiàn)等,代碼如下:
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,作為我們發(fā)布服務(宿主為IIS)讓Android手機調(diào)用, 然后把下面的代碼寫入
<%@ ServiceHost Language="C#" Debug="true" Service="Coreius.CEIMS.AndroidService.AndroidInfoService" %>修改Web.config里面的內(nèi)容:
<?xml version="1.0" encoding="utf-8"?> <configuration><appSettings><add key="ConnectionString" value="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"><!-- 為避免泄漏元數(shù)據(jù)信息,請在部署前將以下值設置為 false 并刪除上面的元數(shù)據(jù)終結點 --><serviceMetadata httpGetEnabled="true"/><!-- 要接收故障異常詳細信息以進行調(diào)試,請將以下值設置為 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"則是為實現(xiàn)可以在發(fā)布可以查看幫助信息????
<behavior name="webHttp"><webHttp helpEnabled="true"/></behavior>(2):為了實現(xiàn)上傳大文件所以我們要如下設置最大值,其中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手機端的代碼是另外一個朋友編寫,所以就把大體的代碼貼出來,大體的原理就是把參數(shù)跟圖片寫入流,然后調(diào)用部署好的WCF服務
代碼一:因為服務器不是公用的,所以下面的IP我就隨便修改的一個;
private void toUploadFile(File file) throws FileNotFoundException {String result = null;requestTime= 0;int res = 0;long requestTime = System.currentTimeMillis();long responseTime = 0;//封裝參數(shù)信息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 blocke.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 blocke1.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}byte[] updata = GpsImagePackage.getPacket(jsonObject.toString(), bytes); //參數(shù)與文件封裝成單個數(shù)據(jù)包HttpClient httpClient = new DefaultHttpClient(httpParameters);HttpPost httpPost = new HttpPost(MyUrl.upload_file);HttpResponse httpResponse;//單個文件流上傳InputStream input = new ByteArrayInputStream( updata );InputStreamEntity reqEntity;reqEntity = new InputStreamEntity(input, -1);reqEntity.setContentType("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 blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.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}//封裝字節(jié)數(shù)組與參數(shù)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轉(zhuǎn)換為字節(jié)數(shù)組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數(shù)組bRefArr轉(zhuǎn)為一個整數(shù),字節(jié)數(shù)組的低位是整型的低字節(jié)位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;} }五:運行效果:
如果,您認為閱讀這篇博客讓您有些收獲,不妨點擊一下右下角的【推薦】按鈕。? 因為,我的寫作熱情也離不開您的肯定支持。
總結
以上是生活随笔為你收集整理的IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是碧根果?
- 下一篇: 部队的伙食怎么样 军营餐厅的口味和菜品?