WebService支持多平台上傳文件的實現


要使用網站上傳文件,在ASP.NET的范疇,我基本上能想到的有兩類,一類是通過HTTP POST請求獲得文件信息,另外一類是通過WebService或者WCF之類的技術對外發布服務。

以前做3G攝像頭項目的時候,做過使用HTTP POST的方式獲得照片,方式很簡單,就是一個aspx文件(其實用asp也行,最開始是用asp實現的,用aspx的時候還出了點幺蛾子),只是客戶端(攝像頭)那邊需要了解POST請求,將圖片做成數據傳輸上來。這個方式也沒什么不好的,就是無奈在集成到系統中的時候總是出點問題,想着反正還要做多種客戶端,於是乎改成第二類方式。

 

需求是要能夠實現多個平台(PC,Android,iOS)的文件傳輸。

我說用WCF吧,之前我用來着,容易上手,但是其他人覺得WCF可能不太容易與非.NET平台互通(沒深入探究,但是網上看到過有人用android調用WCF的,以后有時間再探討),於是乎老老實實的用WebService。

Android調用webservice好像也有兩種方式,我們實現的是用ksoap2調用,首先我需要編寫WEBSERVICE。

文件用什么參數傳遞呢?

  1. 簡單暴力byte[],使用File類或者FileStream類可以很容易將文件流匯入byte數組,直接傳遞。
  2. 不簡單但是暴力string,使用某種方式將文件變成string,再進行傳輸。
  3. 其他方法,類似object?或者別的什么。

這里有序列化的知識,我還沒深入體會,說說自己的看法吧:

首先序列化個人看來就是把對象什么的變得可以存儲和傳輸,有了這個就能夠很方便的實現一些網絡應用。然后就是說KSOAP2對基本的數據類型都能夠序列化,我看到string了,但是也不知道支持還是不支持byte[]型。

回到正題,干脆2個都來吧,反正也不差多少事。

 

由於自己有點疑慮,所以先實現了第二種,通過某種方式---base64編碼解碼。通過這個編碼可以將BYTE變成能夠直接網絡傳輸的string,server端收到數據之后解碼就能夠得到原始byte[]。以下列出web端函數。

[WebMethod(MessageName = "UploadSmallString")]
        public bool UploadSmallString(string fileName, string serializedData)
        {
            try
            {
                byte[] receivedBytes = Convert.FromBase64String(serializedData);
                using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    fs.Write(receivedBytes, 0, receivedBytes.Length);
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

客戶端用base64編碼就可以了,網上找找很多。細心的客官可能看到函數名SmallString,對的,這個適用於文件不太大的時候傳輸,傳輸很大的文件呢?

分塊!分塊傳輸的好處在於能夠支持斷點續傳,說說客戶端的實現思路:

1.判斷文件大小
2.是否適用於分塊傳輸
3.調用服務進行操作

然后服務器端呢,寫個重載吧,可是試了試不成功,參見http://www.cnblogs.com/menglin2010/archive/2012/03/29/2421445.html中說不太支持,要改,用[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]如果改成None用以支持重載的話,又怕出現兼容性問題,老老實實的吧還。

/// <summary>
        /// 使用BASE64編碼接收分塊傳輸的大文件
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="serializedData">BASE64數據</param>
        /// <param name="blockSerial">用以識別文件塊的ID</param>
        /// <returns>對應成功文件塊ID,不成功便成-1</returns>
        [WebMethod(MessageName = "UploadBlobString", Description = "支持大文件傳輸的方法,blockserial為0將創建新文件,這也是默認行為")]
        public int UploadBlobString(string fileName, string serializedData, int blockSerial = 0)
        {
            try
            {
                byte[] receivedBytes = Convert.FromBase64String(serializedData);
                if (blockSerial == 0)
                {
                    using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.Create))
                    {
                        fs.Write(receivedBytes, 0, receivedBytes.Length);
                    }
                }
                else
                {
                    using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.Append))
                    {
                        fs.Write(receivedBytes, 0, receivedBytes.Length);
                    }
                }
                return blockSerial;
            }
            catch
            {
                return -1;
            }
        }

琢磨了一下,好像這個完全可以替代前一個方法,是用.NET默認參數的特性,指定blockSerial默認為0。如果客戶端中斷了,續傳的時候從斷點blockSerial開始就OK了。

 

接下來說說第一種,使用bye[]的方式。

[WebMethod(MessageName = "UploadSmallByte", Description = "直接發送BYTE數組存儲")]
        public bool UploadSmallByte(string fileName, byte[] fileBytes)
        {
            try
            {
                using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    fs.Write(fileBytes, 0, fileBytes.Length);
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

這種方式我沒怎么測試過,但是有一個有意思的事情,就是如果ANDROID編碼BASE64后的string直接傳遞給byte[]參數,這個函數依然可以正常工作,上傳的圖片還是可以正常顯示,很是詭異呀,想在.net下試一試,直接由於類型不同,不能編譯,以后有機會再琢磨琢磨。

 

P.S. BASE64方式的代碼經過測試能夠在ANDROID平台和PC平台下通過,iOS等待BASE64實現(貌似沒有內部的BASE64編碼方法),從原理上應該沒問題,歡迎大家討論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM