C# HTTP系列11 以普通文件流方式上传文件远程服务器

应用程序中上传附件是最常使用的操作之一,ASP.NET客户端一般通过上传控件实现,

<input type="file" id="fileUpload" runat="server" />

后台C#使用以下方式将文件保存到服务上

1 HttpFileCollection files = HttpContext.Current.Request.Files;
2 HttpPostedFile postedFile = files["fileUpload"];
3 postedFile.SaveAs(postedFile.FileName);

上述的场景是简单的管理系统与网站中最常用的方式将客户端的文件上传到IIS服务器的指定目录下。

随着云端应用的发展与普及,第三方应用平台或者开发平台部署在云服务器上,例如阿里云、腾讯云、七牛云、青云等。第三方对外开放的应用平台大都是提供Restful API供开发者调用以上传(本地或者远端文件)或下载业务数据进行业务开发。

传统应用程序的上传控件方式在云端应用程序中针对附件上传与下载完全不适用。

下面提供一种通用的上传附件的方式:

 1 /// <summary>
 2 ///  将数据缓冲区(一般是指文件流或内存流对应的字节数组)上载到由 URI 标识的资源。(包含body数据)
 3 /// </summary>
 4 /// <param name="url">请求目标URL</param>
 5 /// <param name="data">主体数据(字节数据)</param>
 6 /// <param name="method">请求的方法。请使用 WebRequestMethods.Http 的枚举值</param>
 7 /// <param name="contentType"><see langword="Content-type" /> HTTP 标头的值。请使用 ContentType 类的常量来获取。默认为 application/octet-stream</param>
 8 /// <returns>HTTP-POST的响应结果</returns>
 9 public HttpResult UploadData(string url, byte[] data, string method = WebRequestMethods.Http.Post, string contentType = HttpContentType.APPLICATION_OCTET_STREAM)
10 {
11     HttpResult httpResult = new HttpResult();
12     HttpWebRequest httpWebRequest = null;
13 
14     try
15     {
16         httpWebRequest = WebRequest.Create(url) as HttpWebRequest;
17         httpWebRequest.Method = method;
18         httpWebRequest.Headers = HeaderCollection;
19         httpWebRequest.CookieContainer = CookieContainer;
20         httpWebRequest.ContentLength = data.Length;
21         httpWebRequest.ContentType = contentType;
22         httpWebRequest.UserAgent = _userAgent;
23         httpWebRequest.AllowAutoRedirect = _allowAutoRedirect;
24         httpWebRequest.ServicePoint.Expect100Continue = false;
25 
26         if (data != null)
27         {
28             httpWebRequest.AllowWriteStreamBuffering = true;
29             using (Stream requestStream = httpWebRequest.GetRequestStream())
30             {
31                 requestStream.Write(data, 0, data.Length);
32                 requestStream.Flush();
33             }
34         }
35 
36         HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
37         if (httpWebResponse != null)
38         {
39             GetResponse(ref httpResult, httpWebResponse);
40             httpWebResponse.Close();
41         }
42     }
43     catch (WebException webException)
44     {
45         GetWebExceptionResponse(ref httpResult, webException);
46     }
47     catch (Exception ex)
48     {
49         GetExceptionResponse(ref httpResult, ex, method, contentType);
50     }
51     finally
52     {
53         if (httpWebRequest != null)
54         {
55             httpWebRequest.Abort();
56         }
57     }
58 
59     return httpResult;
60 }

借助该方法,又衍生出一下2中重载方式:

重载1:将指定的本地文件上载到具有指定的 URI 的资源。(包含body数据)

 1 /// <summary>
 2 ///  将指定的本地文件上载到具有指定的 URI 的资源。(包含body数据)
 3 /// </summary>
 4 /// <param name="url">请求目标URL</param>
 5 /// <param name="fileFullName">待上传的文件(包含全路径的完全限定名)</param>
 6 /// <param name="method">请求的方法。请使用 WebRequestMethods.Http 的枚举值</param>
 7 /// <param name="contentType"><see langword="Content-type" /> HTTP 标头的值。请使用 ContentType 类的常量来获取。默认为 application/octet-stream</param>
 8 /// <returns>HTTP-POST的响应结果</returns>
 9 public HttpResult UploadFile(string url, string fileFullName, string method = WebRequestMethods.Http.Post, string contentType = HttpContentType.APPLICATION_OCTET_STREAM)
10 {
11     HttpResult httpResult = new HttpResult();
12     if (!File.Exists(fileFullName))
13     {
14         httpResult.Status = HttpResult.STATUS_FAIL;
15 
16         httpResult.RefCode = (int)HttpStatusCode2.USER_FILE_NOT_EXISTS;
17         httpResult.RefText = HttpStatusCode2.USER_FILE_NOT_EXISTS.GetCustomAttributeDescription();
18     }
19     else
20     {
21         FileStream fileStream = new FileStream(fileFullName, FileMode.Open, FileAccess.Read);
22         byte[] data = fileStream.ToByteArray();
23         httpResult = UploadData(url, data, method, contentType);
24     }
25 
26     return httpResult;
27 }

重载2: 将指定的数据流对象(一般指文件流或内存流)上载到具有指定的 URI 的资源。(包含body数据)

 1 /// <summary>
 2 ///  将指定的数据流对象(一般指文件流或内存流)上载到具有指定的 URI 的资源。(包含body数据)
 3 /// </summary>
 4 /// <param name="url">请求目标URL</param>
 5 /// <param name="stream">一般指文件流或内存流</param>
 6 /// <param name="method">请求的方法。请使用 WebRequestMethods.Http 的枚举值</param>
 7 /// <param name="contentType"><see langword="Content-type" /> HTTP 标头的值。请使用 ContentType 类的常量来获取。默认为 application/octet-stream</param>
 8 /// <returns>HTTP-POST的响应结果</returns>
 9 public HttpResult UploadStream(string url, Stream stream, string method = WebRequestMethods.Http.Post, string contentType = HttpContentType.APPLICATION_OCTET_STREAM)
10 {
11     HttpResult httpResult = new HttpResult();
12     if (stream == null)
13     {
14         httpResult.Status = HttpResult.STATUS_FAIL;
15 
16         httpResult.RefCode = (int)HttpStatusCode2.USER_STREAM_NULL;
17         httpResult.RefText = HttpStatusCode2.USER_STREAM_NULL.GetCustomAttributeDescription();
18     }
19     else
20     {
21         byte[] data = stream.ToByteArray();
22         httpResult = UploadData(url, data, method, contentType);
23     }
24 
25     return httpResult;
26 }

其中 UploadData() 调用了 GetResponse()、GetWebExceptionResponse()、GetExceptionResponse()方法

 1 /// <summary>
 2 /// 获取HTTP的响应信息
 3 /// </summary>
 4 /// <param name="httpResult">即将被HTTP请求封装函数返回的HttpResult变量</param>
 5 /// <param name="httpWebResponse">正在被读取的HTTP响应</param>
 6 private void GetResponse(ref HttpResult httpResult, HttpWebResponse httpWebResponse)
 7 {
 8     httpResult.HttpWebResponse = httpWebResponse;
 9     httpResult.Status = HttpResult.STATUS_SUCCESS;
10     httpResult.StatusDescription = httpWebResponse.StatusDescription;
11     httpResult.StatusCode = (int)httpWebResponse.StatusCode;
12 
13     if (ReadMode == ResponseReadMode.Binary)
14     {
15         int len = (int)httpWebResponse.ContentLength;
16         httpResult.Data = new byte[len];
17         int bytesLeft = len;
18         int bytesRead = 0;
19 
20         using (BinaryReader br = new BinaryReader(httpWebResponse.GetResponseStream()))
21         {
22             while (bytesLeft > 0)
23             {
24                 bytesRead = br.Read(httpResult.Data, len - bytesLeft, bytesLeft);
25                 bytesLeft -= bytesRead;
26             }
27         }
28     }
29     else
30     {
31         using (StreamReader sr = new StreamReader(httpWebResponse.GetResponseStream()))
32         {
33             httpResult.Text = sr.ReadToEnd();
34         }
35     }
36 }
 1 /// <summary>
 2 /// 获取HTTP访问网络期间发生错误时引发的异常响应信息
 3 /// </summary>
 4 /// <param name="httpResult">即将被HTTP请求封装函数返回的HttpResult变量</param>
 5 /// <param name="webException">访问网络期间发生错误时引发的异常对象</param>
 6 private void GetWebExceptionResponse(ref HttpResult httpResult, WebException webException)
 7 {
 8     HttpWebResponse exResponse = webException.Response as HttpWebResponse;
 9     if (exResponse != null)
10     {
11         httpResult.HttpWebResponse = exResponse;
12         httpResult.Status = HttpResult.STATUS_FAIL;
13         httpResult.StatusDescription = exResponse.StatusDescription;
14         httpResult.StatusCode = (int)exResponse.StatusCode;
15 
16         httpResult.RefCode = httpResult.StatusCode;
17         using (StreamReader sr = new StreamReader(exResponse.GetResponseStream(), EncodingType))
18         {
19             httpResult.Text = sr.ReadToEnd();
20             httpResult.RefText = httpResult.Text;
21         }
22 
23         exResponse.Close();
24     }
25 }
/// <summary>
/// 获取HTTP的异常响应信息
/// </summary>
/// <param name="httpResult">即将被HTTP请求封装函数返回的HttpResult变量</param>
/// <param name="ex">异常对象</param>
/// <param name="method">HTTP请求的方式</param>
/// <param name="contentType">HTTP的标头类型</param>
private void GetExceptionResponse(ref HttpResult httpResult, Exception ex, string method, string contentType = "")
{
    contentType = string.IsNullOrWhiteSpace(contentType) ? string.Empty : "-" + contentType;
    StringBuilder sb = new StringBuilder();
    sb.AppendFormat("[{0}] [{1}] [HTTP-" + method + contentType + "] Error:  ", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"), _userAgent);
    Exception exception = ex;
    while (exception != null)
    {
        sb.AppendLine(exception.Message + " ");
        exception = exception.InnerException;
    }
    sb.AppendLine();

    httpResult.HttpWebResponse = null;
    httpResult.Status = HttpResult.STATUS_FAIL;

    httpResult.RefCode = (int)HttpStatusCode2.USER_UNDEF;
    httpResult.RefText += sb.ToString();
}

 

C# HTTP系列11 以普通文件流方式上传文件远程服务器

上一篇:Android中SQLite应用详解


下一篇:游戏UI框架设计(五): 配置管理与应用