IOS調用WCF提供的服務方法,可是方法的參數是WCF那邊自定義的對象,這樣有辦法調用麼,若是能夠IOS應該怎麼傳參呢?請問有了解的麼,

最近作一個項目後端使用WCF接收Android手機拍照並帶其它參數保存到服務器裏;恰好把最近學習的WCF利用上,本覺得是個比較簡單的功能應該很好實現,沒想到其中碰到很多問題,在網上搜索好久一直沒有想到的解決方案,最後實現對數據流的分段寫入而後後端再來解析流實現的此功能;後端運用WCF中的REST來接收數據;REST仍是比較簡單的知識,如果不懂能夠簡單網上了解一下;下面咱們先了解一些本次運用到的理論知識:html

 

一:理論知識web

因爲低層協議特性限制,WCF的流模式只支持以下四種:1:BasicHttpBinding 2:NetTcpBinding 3:NetNamedPipeBinding 4:WebHttpBindingjson

1.設置TransferMode。它支持四種模式(Buffered、Streamed、StreamedRequest、StreamedResponse),請根據具體狀況設置成三種Stream模式之一。後端

2.修改MaxReceivedMessageSize。該值默認大小爲64k,所以,當傳輸數據大於64k時,則拋出CommunicationException異常。  數組

3.修改receiveTimeout 和sendTimeout。大數據傳送時間較長,須要修改這兩個值,以避免傳輸超時服務器

 

二:解決問題app

WCF若是使用Stream作爲參數時只能惟一一個,不能有其它另外的參數,這個也是本次碰到要重點解決的一個問題;但是咱們Android手機除的圖片還要有其它的參數,最後決定採用手機端把參數跟圖片都一塊兒寫入Stream裏面,後端WCF再來解析這個參數的流;oop

下面就是定義好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 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 = 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 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;
     }
}

 

五:運行效果:

 

 

若是,您認爲閱讀這篇博客讓您有些收穫,不妨點擊一下右下角的【推薦】按鈕。  由於,個人寫做熱情也離不開您的確定支持。

相關文章
相關標籤/搜索