Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> WCF與Android實現圖片上傳並傳參實踐

WCF與Android實現圖片上傳並傳參實踐

編輯:Android開發實例

最近做一個項目後端使用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方式進行接收:

  1. using System.ServiceModel;  
  2. using System.Runtime.Serialization;  
  3. using System.ServiceModel.Web;  
  4. using System.IO;  
  5.  
  6. namespace Coreius.CEIMS.AndroidInterface  
  7. {  
  8.     [ServiceContract]  
  9.     public interface IAndroidInfo  
  10.     {  
  11.          [WebInvoke(UriTemplate = "GpsUpFile", Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json,   
  12. ResponseFormat = WebMessageFormat.Json)]  
  13.         bool GpsUpFile(Stream ImageContext);  
  14.     }  

2:根據契約我們定義服務的內容,接收一個流的參數內容,首先把這個Stream轉化成字節,然後根據我們先前約定好的內容獲得第一個字節的值,再根據此值定義我們另外三個參數的字節長度,再通過JSON轉換格式把它裡面的三個參數值取出來,最後其它字節是存放一張手機拍的照片,把它存放在於們服務器D盤文件夾下

  1. using System.Linq;  
  2. using System.Text;  
  3. using System.ServiceModel;  
  4. using System.ServiceModel.Web;  
  5. using System.IO;  
  6. using Newtonsoft.Json;  
  7.  
  8. namespace Coreius.CEIMS.AndroidService  
  9. {  
  10.     public class AndroidInfoService:IAndroidInfo  
  11.     {  
  12.  
  13.       public bool GpsUpFile(Stream ImageContext)  
  14.         {  
  15.             byte[] m_Bytes = ReadToEnd(ImageContext);  
  16.             int len = (int)m_Bytes[0];  
  17.  
  18.             byte[] data = m_Bytes.Skip(1).Take(len).ToArray();  
  19.             string Jsonstr = System.Text.Encoding.Default.GetString(data);  
  20.  
  21.             JsonModel item = JsonConvert.DeserializeObject<JsonModel>(Jsonstr);  
  22.             string ImageType=item.type;  
  23.             string EmployeeID=item.EmployeeID;  
  24.             string TaskID=item.TaskID;  
  25.  
  26.             byte[] Imagedata = m_Bytes.Skip(1 + len).ToArray();  
  27.  
  28.             string DiskName = "d:";  
  29.             string FileAddress = "\\UpLoad\\";  
  30.             string LocationAddress = DiskName + FileAddress;  
  31.             if (!DirFileHelper.IsExistDirectory(LocationAddress))  
  32.             {  
  33.                 DirFileHelper.CreateDirectory(LocationAddress);  
  34.             }  
  35.  
  36.             string ImageName = DateTime.Now.ToString("yyyyMMddhhmmss.") + ImageType;  
  37.             string ImagePath = LocationAddress + ImageName;  
  38.             if (!File.Exists(ImagePath))  
  39.             {  
  40.                 try 
  41.                 {  
  42.                     System.IO.File.WriteAllBytes(ImagePath, Imagedata);  
  43.                     ImageContext.Close();  
  44.                     return true;  
  45.                 }  
  46.                 catch 
  47.                 {  
  48.                     return false;  
  49.                 }  
  50.             }  
  51.             else 
  52.             {  
  53.                 return false;  
  54.             }  
  55.         }  
  56.     }  

上面的代碼用到幾個方法,比如把流轉化成字節、把JSON轉化成實現等,代碼如下:

  1. public byte[] ReadToEnd(System.IO.Stream stream)  
  2.         {  
  3.             long originalPosition = 0;  
  4.  
  5.             if (stream.CanSeek)  
  6.             {  
  7.                 originalPosition = stream.Position;  
  8.                 stream.Position = 0;  
  9.             }  
  10.  
  11.             try 
  12.             {  
  13.                 byte[] readBuffer = new byte[4096];  
  14.  
  15.                 int totalBytesRead = 0;  
  16.                 int bytesRead;  
  17.  
  18.                 while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)  
  19.                 {  
  20.                     totalBytesRead += bytesRead;  
  21.  
  22.                     if (totalBytesRead == readBuffer.Length)  
  23.                     {  
  24.                         int nextByte = stream.ReadByte();  
  25.                         if (nextByte != -1)  
  26.                         {  
  27.                             byte[] temp = new byte[readBuffer.Length * 2];  
  28.                             Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);  
  29.                             Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);  
  30.                             readBuffer = temp;  
  31.                             totalBytesRead++;  
  32.                         }  
  33.                     }  
  34.                 }  
  35.  
  36.                 byte[] buffer = readBuffer;  
  37.                 if (readBuffer.Length != totalBytesRead)  
  38.                 {  
  39.                     buffer = new byte[totalBytesRead];  
  40.                     Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);  
  41.                 }  
  42.                 return buffer;  
  43.             }  
  44.             finally 
  45.             {  
  46.                 if (stream.CanSeek)  
  47.                 {  
  48.                     stream.Position = originalPosition;  
  49.                 }  
  50.             }  
  51.         }  
  52.  
  53.  
  54.  
  55.     public class JsonModel  
  56.     {  
  57.         public string type { get; set; }  
  58.         public string EmployeeID { get; set; }  
  59.         public string TaskID { get; set; }  
  60.     } 

3:新建一個文本,然後修改其後綴名為.svc,作為我們發布服務(宿主為IIS)讓Android手機調用, 然後把下面的代碼寫入

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

修改Web.config裡面的內容:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <configuration> 
  3.   <appSettings> 
  4.     <add key="ConnectionString" value="server=127.0.0.1;database=Coreius;uid=sa;pwd=admin"/> 
  5.   </appSettings> 
  6.   <system.web> 
  7.     <compilation debug="true" targetFramework="4.0" /> 
  8.   </system.web> 
  9.   <system.serviceModel> 
  10.     <behaviors> 
  11.       <endpointBehaviors> 
  12.         <behavior name="webHttp"> 
  13.           <webHttp helpEnabled="true"/> 
  14.         </behavior> 
  15.       </endpointBehaviors> 
  16.       <serviceBehaviors> 
  17.         <behavior name="MapConfigBehavior"> 
  18.           <!-- 為避免洩漏元數據信息,請在部署前將以下值設置為 false 並刪除上面的元數據終結點 --> 
  19.           <serviceMetadata httpGetEnabled="true"/> 
  20.           <!-- 要接收故障異常詳細信息以進行調試,請將以下值設置為 true。在部署前設置為 false 以避免洩漏異常信息 --> 
  21.           <serviceDebug includeExceptionDetailInFaults="true"/> 
  22.           <dataContractSerializer maxItemsInObjectGraph="2147483647"/> 
  23.         </behavior> 
  24.       </serviceBehaviors> 
  25.     </behaviors> 
  26.  
  27.     <bindings> 
  28.       <webHttpBinding> 
  29.         <binding name="webHttpBindConfig" receiveTimeout="00:30:00" sendTimeout="00:30:00" maxReceivedMessageSize="104857600" transferMode="Streamed"> 
  30.           <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"/> 
  31.           <security mode="None"></security> 
  32.         </binding> 
  33.       </webHttpBinding> 
  34.     </bindings> 
  35.     <services> 
  36.       <service name="Coreius.CEIMS.AndroidService.AndroidInfoService" behaviorConfiguration="MapConfigBehavior"> 
  37.         <endpoint binding="webHttpBinding" contract="Coreius.CEIMS.AndroidInterface.IAndroidInfo" bindingConfiguration="webHttpBindConfig"   
  38.  
  39. behaviorConfiguration="webHttp"/>   
  40.       </service> 
  41.     </services> 
  42.   </system.serviceModel> 
  43. </configuration> 

此處有些要注意的地方:

(1):此處采用的是webHttpBinding 所以一定要設置behaviorConfiguration才會有效果,其中helpEnabled="true"則是為實現可以在發布可以查看幫助信息    

  1. <behavior name="webHttp"> 
  2.   <webHttp helpEnabled="true"/> 
  3. </behavior> 

(2):為了實現上傳大文件所以我們要如下設置最大值,其中security是設置訪問服務的認證,此處是把它設置成為不認證,transferMode就是設置運用流的模式

  1. <webHttpBinding> 
  2.         <binding name="webHttpBindConfig" receiveTimeout="00:30:00" sendTimeout="00:30:00" maxReceivedMessageSize="104857600" transferMode="Streamed"> 
  3.           <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"/> 
  4.           <security mode="None"></security> 
  5.         </binding> 
  6.       </webHttpBinding> 

:編寫完上面的代碼後就可以服務器IIS上部署這個WCF服務:

四:Android編碼

由於Android手機端的代碼是另外一個朋友編寫,所以就把大體的代碼貼出來,大體的原理就是把參數跟圖片寫入流(圖片進行壓縮處理),然後調用部署好的WCF服務

代碼一:因為服務器不是公用的,所以下面的IP我就隨便修改的一個;

  1. private void toUploadFile(File file) throws FileNotFoundException {   
  2.         String result = null;   
  3.         requestTime= 0;   
  4.         int res = 0;   
  5.         long requestTime = System.currentTimeMillis();   
  6.         long responseTime = 0;   
  7.             
  8.         //封裝參數信息   
  9.         JSONObject jsonObject = new JSONObject();   
  10.         try {   
  11.             jsonObject.put("EmployeeID", MainActivity.guid);   
  12.             jsonObject.put("TaskID", "e52df9b4-ee3b-46c5-8387-329b76356641");   
  13.             String[] type = file.getName().split("\\.");   
  14.             jsonObject.put("type", type[type.length-1]);   
  15.         } catch (JSONException e) {   
  16.             // TODO Auto-generated catch block   
  17.             e.printStackTrace();   
  18.         }   
  19.             
  20.         /**上傳文件*/ 
  21.         HttpParams httpParameters = new BasicHttpParams();   
  22.         HttpConnectionParams.setConnectionTimeout(httpParameters, 1000*30);   
  23.         HttpConnectionParams.setSoTimeout(httpParameters, 1000*30);   
  24.         HttpConnectionParams.setTcpNoDelay(httpParameters, true);   
  25.                 
  26.         String path = PictureUtil.zipNewImage(file);    //壓縮文件後返回的文件路徑   
  27.         byte[] bytes = null;   
  28.         InputStream is;   
  29.         File myfile = new File(path);   
  30.         try {   
  31.             is = new FileInputStream(path);   
  32.             bytes = new byte[(int) myfile.length()];   
  33.             int len = 0;   
  34.             int curLen = 0;   
  35.             while ((len = is.read(bytes)) != -1) {   
  36.                 curLen += len;   
  37.                 is.read(bytes);   
  38.             }   
  39.             is.close();   
  40.         } catch (FileNotFoundException e1) {   
  41.             // TODO Auto-generated catch block   
  42.             e1.printStackTrace();   
  43.         } catch (IOException e) {   
  44.             // TODO Auto-generated catch block   
  45.             e.printStackTrace();   
  46.         }   
  47.         byte[] updata = GpsImagePackage.getPacket(jsonObject.toString(), bytes);    //參數與文件封裝成單個數據包   
  48.         HttpClient httpClient = new DefaultHttpClient(httpParameters);   
  49.         HttpPost httpPost = new HttpPost(MyUrl.upload_file);   
  50.         HttpResponse httpResponse;   
  51.         //單個文件流上傳   
  52.         InputStream input = new ByteArrayInputStream( updata );   
  53.         InputStreamEntity reqEntity;   
  54.         reqEntity = new InputStreamEntity(input, -1);   
  55.         reqEntity.setContentType("binary/octet-stream");   
  56.         reqEntity.setChunked(true);   
  57.         httpPost.setEntity(reqEntity);   
  58.         try {   
  59.             httpResponse = httpClient.execute(httpPost);   
  60.             responseTime = System.currentTimeMillis();   
  61.             this.requestTime = (int) ((responseTime-requestTime)/1000);   
  62.             res = httpResponse.getStatusLine().getStatusCode();   
  63.             if (httpResponse.getStatusLine().getStatusCode() ==200) {   
  64.                 Log.e(TAG, "request success");   
  65.                 Log.e(TAG, "result : " + result);   
  66.                 return;   
  67.             } else {   
  68.                 Log.e(TAG, "request error");   
  69.                 sendMessage(UPLOAD_SERVER_ERROR_CODE,"上傳失敗:code=" + res);   
  70.                 return;   
  71.             }   
  72.             } catch (ClientProtocolException e) {   
  73.                 // TODO Auto-generated catch block   
  74.                 e.printStackTrace();   
  75.             } catch (IOException e) {   
  76.                 // TODO Auto-generated catch block   
  77.                 e.printStackTrace();   
  78.             }   
  79.     }   
  80.     
  81. package com.anthony.util;   
  82. /**   
  83.  * 服務器端接口   
  84.  * @author YWJ   
  85.  *   
  86.  */ 
  87. public class MyUrl {   
  88.     public static String upload_GPS = http://122.199.19.23:8088/AndroidInfoService.svc/GpsUpFile;   

代碼二:

  1. package com.anthony.util;   
  2.     
  3. public class GpsImagePackage {   
  4.     public GpsImagePackage() {   
  5.         // TODO Auto-generated constructor stub   
  6.     }   
  7.         
  8.     //封裝字節數組與參數   
  9.     public static byte[] getPacket(String json,byte[] image){   
  10.             
  11.         byte[] jsonb = json.getBytes();   
  12.         int length = image.length + jsonb.length;   
  13.         System.out.println(image.length +"    "+ jsonb.length);   
  14.         byte[] bytes = new byte[length+1];   
  15.         byte[] lengthb = InttoByteArray(jsonb.length, 1);   
  16.         System.arraycopy(lengthb, 0, bytes, 0, 1);   
  17.         System.arraycopy(jsonb, 0, bytes, 1, jsonb.length);   
  18.         System.arraycopy(image, 0, bytes, 1+jsonb.length, image.length);   
  19.         return bytes;   
  20.             
  21.     }   
  22.         
  23.     //將int轉換為字節數組   
  24.     public static byte[] InttoByteArray(int iSource, int iArrayLen) {   
  25.             
  26.         byte[] bLocalArr = new byte[iArrayLen];   
  27.         for ( int i = 0; (i < 4) && (i < iArrayLen); i++) {   
  28.              bLocalArr[i] = (byte)( iSource>>8*i & 0xFF );   
  29.         }   
  30.          return bLocalArr;   
  31.     }   
  32.     
  33.      // 將byte數組bRefArr轉為一個整數,字節數組的低位是整型的低字節位   
  34.      public static int BytestoInt(byte[] bRefArr) {   
  35.              
  36.          int iOutcome = 0;   
  37.          byte bLoop;   
  38.          for ( int i =0; i<bRefArr.length ; i++) {   
  39.             bLoop = bRefArr[i];   
  40.             iOutcome+= (bLoop & 0xFF) << (8 * i);   
  41.          }   
  42.         return iOutcome;   
  43.      }   
  44. }   
  45.  
  46.    
  47.  

五:運行效果:

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved