直接上代碼,包各位看客能用!!!
1.首先請求參數的封裝
/// <summary> /// 上傳文件 - 請求參數類 /// </summary> public class UploadParameterType { public UploadParameterType() { FileNameKey = "fileName"; Encoding = Encoding.UTF8; PostParameters = new Dictionary<string, string>(); } /// <summary> /// 上傳地址 /// </summary> public string Url { get; set; } /// <summary> /// 文件名稱key /// </summary> public string FileNameKey { get; set; } /// <summary> /// 文件名稱value /// </summary> public string FileNameValue { get; set; } /// <summary> /// 編碼格式 /// </summary> public Encoding Encoding { get; set; } /// <summary> /// 上傳文件的流 /// </summary> public Stream UploadStream { get; set; } /// <summary> /// 上傳文件 攜帶的參數集合 /// </summary> public IDictionary<string, string> PostParameters { get; set; } }
2.HttpWebRequest 封裝
/// <summary> /// Http上傳文件類 - HttpWebRequest封裝 /// </summary> public class HttpUploadClient { /// <summary> /// 上傳執行 方法 /// </summary> /// <param name="parameter">上傳文件請求參數</param> public static string Execute(UploadParameterType parameter) { using (MemoryStream memoryStream = new MemoryStream()) { // 1.分界線 string boundary = string.Format("----{0}", DateTime.Now.Ticks.ToString("x")), // 分界線可以自定義參數 beginBoundary = string.Format("--{0}\r\n", boundary), endBoundary = string.Format("\r\n--{0}--\r\n", boundary); byte[] beginBoundaryBytes = parameter.Encoding.GetBytes(beginBoundary), endBoundaryBytes = parameter.Encoding.GetBytes(endBoundary); // 2.組裝開始分界線數據體 到內存流中 memoryStream.Write(beginBoundaryBytes, 0, beginBoundaryBytes.Length); // 3.組裝 上傳文件附加攜帶的參數 到內存流中 if (parameter.PostParameters != null && parameter.PostParameters.Count > 0) { foreach (KeyValuePair<string, string> keyValuePair in parameter.PostParameters) { string parameterHeaderTemplate = string.Format("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n{2}", keyValuePair.Key, keyValuePair.Value, beginBoundary); byte[] parameterHeaderBytes = parameter.Encoding.GetBytes(parameterHeaderTemplate); memoryStream.Write(parameterHeaderBytes, 0, parameterHeaderBytes.Length); } } // 4.組裝文件頭數據體 到內存流中 string fileHeaderTemplate = string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", parameter.FileNameKey, parameter.FileNameValue); byte[] fileHeaderBytes = parameter.Encoding.GetBytes(fileHeaderTemplate); memoryStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length); // 5.組裝文件流 到內存流中 byte[] buffer = new byte[1024 * 1024 * 1]; int size = parameter.UploadStream.Read(buffer, 0, buffer.Length); while (size > 0) { memoryStream.Write(buffer, 0, size); size = parameter.UploadStream.Read(buffer, 0, buffer.Length); } // 6.組裝結束分界線數據體 到內存流中 memoryStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length); // 7.獲取二進制數據 byte[] postBytes = memoryStream.ToArray(); memoryStream.Close(); GC.Collect(); // 8.HttpWebRequest 組裝 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(new Uri(parameter.Url, UriKind.RelativeOrAbsolute)); webRequest.AllowWriteStreamBuffering = false; webRequest.Method = "POST"; webRequest.Timeout = 1800000; webRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary); webRequest.ContentLength = postBytes.Length; if (Regex.IsMatch(parameter.Url, "^https://")) { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult; } // 9.寫入上傳請求數據 using (Stream requestStream = webRequest.GetRequestStream()) { requestStream.Write(postBytes, 0, postBytes.Length); requestStream.Close(); } // 10.獲取響應 using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) { using (StreamReader reader = new StreamReader(webResponse.GetResponseStream(), parameter.Encoding)) { string body = reader.ReadToEnd(); reader.Close(); return body; } } } } /// <summary> /// 上傳執行 方法 /// </summary> /// <param name="parameter">上傳文件請求參數</param> public static string Execute2(UploadParameterType parameter) { // 1.分界線 string boundary = string.Format("----{0}", DateTime.Now.Ticks.ToString("x")), // 分界線可以自定義參數 beginBoundary = string.Format("--{0}\r\n", boundary), endBoundary = string.Format("\r\n--{0}--\r\n", boundary); byte[] beginBoundaryBytes = parameter.Encoding.GetBytes(beginBoundary), endBoundaryBytes = parameter.Encoding.GetBytes(endBoundary); byte[] postBytes = new byte[] { }; using (MemoryStream memoryStream = new MemoryStream()) { // 2.組裝開始分界線數據體 到內存流中 memoryStream.Write(beginBoundaryBytes, 0, beginBoundaryBytes.Length); // 3.組裝 上傳文件附加攜帶的參數 到內存流中 if (parameter.PostParameters != null && parameter.PostParameters.Count > 0) { foreach (KeyValuePair<string, string> keyValuePair in parameter.PostParameters) { string parameterHeaderTemplate = string.Format("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n{2}", keyValuePair.Key, keyValuePair.Value, beginBoundary); byte[] parameterHeaderBytes = parameter.Encoding.GetBytes(parameterHeaderTemplate); memoryStream.Write(parameterHeaderBytes, 0, parameterHeaderBytes.Length); } } // 4.組裝文件頭數據體 到內存流中 string fileHeaderTemplate = string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", parameter.FileNameKey, parameter.FileNameValue); byte[] fileHeaderBytes = parameter.Encoding.GetBytes(fileHeaderTemplate); memoryStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length); // 5.組裝結束分界線數據體 到內存流中 //memoryStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length); // 6.獲取二進制數據 postBytes = memoryStream.ToArray(); } // 7.HttpWebRequest 組裝 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(new Uri(parameter.Url, UriKind.RelativeOrAbsolute)); //對發送的數據不使用緩存【重要、關鍵】 webRequest.AllowWriteStreamBuffering = false; webRequest.Method = "POST"; webRequest.Timeout = 1800000; webRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary); webRequest.ContentLength = postBytes.Length + parameter.UploadStream.Length+endBoundaryBytes.Length; if (Regex.IsMatch(parameter.Url, "^https://")) { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult; } // 8.組裝文件流 byte[] buffer = new byte[1024 * 1024 * 1]; int size = parameter.UploadStream.Read(buffer, 0, buffer.Length); Stream requestStream = webRequest.GetRequestStream(); requestStream.Write(postBytes, 0, postBytes.Length); while (size > 0) { requestStream.Write(buffer, 0, size); size = parameter.UploadStream.Read(buffer, 0, buffer.Length); } requestStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length); requestStream.Close(); // 9.獲取響應 using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) { using (StreamReader reader = new StreamReader(webResponse.GetResponseStream(), parameter.Encoding)) { string body = reader.ReadToEnd(); reader.Close(); return body; } } } static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { return true; } }
HttpUploadClient類中兩個Execute2,參考網上,大都用第一個,如果上傳小文件沒問題,要是比較大(百兆以上)就會內存溢出,然後就用流方式。思路是一樣的
3.調用示例:
using (FileStream fs = new FileStream(@"C:\\test.zip", FileMode.Open, FileAccess.Read)) { Dictionary<string, string> postParameter = new Dictionary<string, string>(); postParameter.Add("name", "heshang"); postParameter.Add("param", "1 2 3"); string result = HttpUploadClient.Execute(new UploadParameterType { Url = url, UploadStream = fs, FileNameValue = "test.zip", PostParameters = postParameter }); }
4.接口服務後台接受請求時:
public IHttpActionResult Post() { HttpPostedFile file = HttpContext.Current.Request.Files[0]; string pyPath = HttpContext.Current.Request["name"]; string Params = HttpContext.Current.Request["params"]; file.SaveAs("C:\\test.zip"); return Ok(""); }
5.完美解決大文件上傳