直接上代码,包各位看客能用!!!
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} ", boundary), endBoundary = string.Format(" --{0}-- ", 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}" {1} {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}" Content-Type: application/octet-stream ", 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} ", boundary), endBoundary = string.Format(" --{0}-- ", 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}" {1} {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}" Content-Type: application/octet-stream ", 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.完美解决大文件上传