在基於Http協議的Post請求中,Content-type為application/x-www-form-urlencoded的傳輸只能傳送非檔案的資料。
如果想用Http的Post方法來上傳資料及檔案,需要實現Content-type為multipart/form-data類型的協議程式。
下面是參考了StackOverflow網站上的一個例子,實現了關於用戶端上傳檔案的功能類,代碼如下:
using System;using System.Net;using System.Text;using System.Collections.Generic;using System.IO;namespace ZDWorks.ZDClock.Cloud{ /// <summary> /// 檔案類型資料的內容參數 /// </summary> public class FileParameter { // 檔案內容 public byte[] File { get; set; } // 檔案名稱 public string FileName { get; set; } // 檔案內容類型 public string ContentType { get; set; } public FileParameter(byte[] file) : this(file, null) { } public FileParameter(byte[] file, string filename) : this(file, filename, null) { } public FileParameter(byte[] file, string filename, string contentType) { File = file; FileName = filename; ContentType = contentType; } } /// <summary> /// 資料與檔案http請求 /// </summary> public class HttpMultipartFormRequest { #region Data Members private readonly Encoding DefaultEncoding = Encoding.UTF8; private ResponseCallback m_Callback; private byte[] m_FormData; #endregion #region Constructor public HttpMultipartFormRequest() { } #endregion #region Delegate public delegate void ResponseCallback(string msg); #endregion public void AsyncHttpRequest(string postUri, Dictionary<string, object> postParameters, ResponseCallback callback) { // 隨機序列,用作防止伺服器無法識別資料的起始位置 string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid()); // 設定contentType string contentType = "multipart/form-data; boundary=" + formDataBoundary; // 將資料轉換為byte[]格式 m_FormData = GetMultipartFormData(postParameters, formDataBoundary); // 回呼函數 m_Callback = callback; // 建立http對象 HttpWebRequest request = HttpWebRequest.CreateHttp(new Uri(postUri)); // 設為post請求 request.Method = "POST"; request.ContentType = contentType; // 請求寫入資料流 request.BeginGetRequestStream(GetRequestStreamCallback, request); } private void GetRequestStreamCallback(IAsyncResult ar) { HttpWebRequest request = ar.AsyncState as HttpWebRequest; using (var postStream = request.EndGetRequestStream(ar)) { postStream.Write(m_FormData, 0, m_FormData.Length); postStream.Close(); } request.BeginGetResponse(GetResponseCallback, request); } private void GetResponseCallback(IAsyncResult ar) { // 處理Post請求返回的訊息 try { HttpWebRequest request = ar.AsyncState as HttpWebRequest; HttpWebResponse response = request.EndGetResponse(ar) as HttpWebResponse; using (var stream = response.GetResponseStream()) { StreamReader reader = new StreamReader(stream); string msg = reader.ReadToEnd(); if (m_Callback != null) { m_Callback(msg); } } } catch (Exception e) { string a = e.ToString(); if (m_Callback != null) { m_Callback(string.Empty); } } } private byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary) { Stream formDataStream = new MemoryStream(); bool needsCLRF = false; foreach (var param in postParameters) { if (needsCLRF) { formDataStream.Write(DefaultEncoding.GetBytes("\r\n"), 0, DefaultEncoding.GetByteCount("\r\n")); } needsCLRF = true; if (param.Value is FileParameter) { FileParameter fileToUpload = (FileParameter)param.Value; string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n", boundary, param.Key, fileToUpload.FileName ?? param.Key, fileToUpload.ContentType ?? "application/octet-stream"); // 將與檔案相關的header資料寫到stream中 formDataStream.Write(DefaultEncoding.GetBytes(header), 0, DefaultEncoding.GetByteCount(header)); // 將檔案資料直接寫到stream中 formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length); } else { string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", boundary, param.Key, param.Value); formDataStream.Write(DefaultEncoding.GetBytes(postData), 0, DefaultEncoding.GetByteCount(postData)); } } string tailEnd = "\r\n--" + boundary + "--\r\n"; formDataStream.Write(DefaultEncoding.GetBytes(tailEnd), 0, DefaultEncoding.GetByteCount(tailEnd)); // 將Stream資料轉換為byte[]格式 formDataStream.Position = 0; byte[] formData = new byte[formDataStream.Length]; formDataStream.Read(formData, 0, formData.Length); formDataStream.Close(); return formData; } }}