IOS調用WCF提供的服務方法,但是方法的參數是WCF那邊自訂的對象,這樣有辦法調用麼,如果可以IOS應該怎麼傳參呢?請問有瞭解的麼,

來源:互聯網
上載者:User

標籤:des   android   style   class   code   http   

最近做一個項目後端使用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 = 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;            }        }    }}

上面的代碼用到幾個方法,比如把流轉化成位元組、把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="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 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);//參數與檔案封裝成單個資料包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}//封裝位元組數組與參數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;     }}

 

五:運行效果:

 

 

如果,您認為閱讀這篇部落格讓您有些收穫,不妨點擊一下右下角的【推薦】按鈕。  因為,我的寫作熱情也離不開您的肯定支援。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.