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编码方法),从原理上应该没问题,欢迎大家讨论。

posted @ 2014-03-27 14:12  波多尔斯基  阅读(6071)  评论(1编辑  收藏  举报