https://www.cnblogs.com/Dewumu/p/7422338.html
ASP.NET 服务端接收Multipart/form-data文件
在网络编程过程中需要向服务器上传文件。
Multipart/form-data是上传文件的一种方式。
1 /// <summary> 2 /// 上传工程文件 3 /// </summary> 4 /// <returns></returns> 5 public async Task<HttpResponseMessage> UploadProjectFile() 6 { 7 ProjectFile postData = new ProjectFile(); 8 IEnumerable<string> stringValues; 9 //获取请求头文件相关参数 10 Request.Headers.TryGetValues("token", out stringValues); 11 postData.token = stringValues.FirstOrDefault(); 12 13 Request.Headers.TryGetValues("uid", out stringValues); 14 postData.uid = int.Parse(stringValues.FirstOrDefault()); 15 16 Request.Headers.TryGetValues("project_id", out stringValues); 17 postData.project_id = int.Parse(stringValues.FirstOrDefault()); 18 19 Request.Headers.TryGetValues("md5", out stringValues); 20 postData.md5 = stringValues.FirstOrDefault(); 21 22 Request.Headers.TryGetValues("file_name", out stringValues); 23 postData.file_name = stringValues.FirstOrDefault(); 24 //验证Token 25 var result = CheckToken(postData.token); 26 if (!result) 27 { 28 return CreateResponseError(401, "请求拒绝"); 29 } 30 //获取文件名,这里的文件名必须带扩展名 31 string fileName = postData.file_name; 32 33 int projectId = postData.project_id; 34 //获取应用程序的当前工作目录 35 string rootPath = HostingEnvironment.MapPath("~/"); 36 //通过Path类的Combine方法可以合并路径。获取当前工程文件夹地址 37 string directoryPath = Path.Combine(rootPath, "BgerProject", projectId.ToString()); 38 //创建目录时如果目录已存在,则不会重新创建目录,且不会报错。创建目录时会自动创建路径中各级不存在的目录。 39 Directory.CreateDirectory(directoryPath); 40 //获取当前工程文件地址 41 string filePath = Path.Combine(directoryPath, fileName); 42 if (Request.Content.IsMimeMultipartContent()) 43 { 44 Dictionary<string, string> dic = new Dictionary<string, string>(); 45 var provider = new MultipartFormDataMemoryStreamProvider(); 46 47 await Request.Content.ReadAsMultipartAsync(provider); 48 foreach (var item in provider.FileContents) 49 { 50 //Trace.WriteLine(item.Headers.ContentDisposition.FileName);//获取上传文件实际的文件名 51 //Trace.WriteLine("Server file path: " + item.LocalFileName);//获取上传文件在服务上默认的文件名 52 var stream = await item.ReadAsStreamAsync(); 53 if (Path.GetExtension(item.Headers.ContentDisposition.FileName.Replace(""", "")) == ".mp4") 54 { 55 //通过正则表达式判断是视频还是音频 56 Regex regex = new Regex("voice", RegexOptions.Compiled); 57 Match m = regex.Match(item.Headers.ContentDisposition.Name.ToLower()); 58 if (m.Success) 59 { 60 //音频直接保存处理 61 62 //判断是否已存在该音频 63 if (!File.Exists(filePath)) 64 { 65 using (StreamWriter sw = new StreamWriter(filePath)) 66 { 67 stream.CopyTo(sw.BaseStream); 68 sw.Flush(); 69 } 70 } 71 } 72 else 73 { 74 //视频进行压缩处理 75 //保存原片(如果路径不存在,创建路径) 76 77 using (StreamWriter sw = new StreamWriter(filePath)) 78 { 79 stream.CopyTo(sw.BaseStream); 80 sw.Flush(); 81 } 82 //压缩并保存上传的视频 83 //压缩后的存放路径(如果路径不存在,创建路径) 84 ////判断是否已存在该视频 85 //if (!File.Exists(filePath)) 86 //{ 87 // //压缩保存视频 88 // if (!FFMPEGHelper.CreateNewVideo(originalFilePath, filePath)) 89 // { 90 // continue; 91 // }; 92 //} 93 } 94 } 95 else 96 { 97 //保存原片(如果路径不存在,创建路径) 98 99 using (StreamWriter sw = new StreamWriter(filePath)) 100 { 101 stream.CopyTo(sw.BaseStream); 102 sw.Flush(); 103 } 104 //压缩并保存上传的图片 105 //压缩后的存放路径(如果路径不存在,创建路径) 106 107 ////判断是否已存在该图片 108 //if (!File.Exists(filePath)) 109 //{ 110 // var pxLimit = 481; 111 // //判断是否需要压缩 112 // System.Drawing.Image iSource = System.Drawing.Image.FromFile(originalFilePath); 113 // if (iSource.Width <= pxLimit || iSource.Height <= pxLimit) 114 // { 115 // //无需压缩 116 // System.IO.File.Copy(originalFilePath, filePath); 117 // } 118 // else 119 // { 120 // var min = Math.Min((int)iSource.Width, (int)iSource.Height); 121 // if (min > pxLimit) 122 // { 123 // //缩放倍率 124 // var rate = (double)pxLimit / min; 125 // var width = (int)Math.Ceiling(rate * (double)iSource.Width); 126 // var height = (int)Math.Ceiling(rate * (double)iSource.Height); 127 128 // //压缩保存图片 129 // if (!ImageHelper.GetPicThumbnail(originalFilePath, filePath, height, width, 100)) 130 // { 131 // continue; 132 // }; 133 // } 134 // } 135 //} 136 } 137 } 138 return CreateResponse("请求成功"); 139 140 } 141 return CreateResponseError(202,"缺少MIME内容"); 142 143 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Collections.ObjectModel; 6 using System.Collections.Specialized; 7 using System.IO; 8 using System.Net.Http; 9 using System.Net.Http.Headers; 10 using System.Threading; 11 using System.Threading.Tasks; 12 13 namespace BgerServer.Models 14 { 15 /// <summary> 16 /// 与MultipartFormDataStreamProvider对应,但不将文件直接存入指定位置,而是需要自己指定数据流如何保存 17 /// </summary> 18 public class MultipartFormDataMemoryStreamProvider : MultipartStreamProvider 19 { 20 private NameValueCollection _formData = new NameValueCollection(); 21 private Collection<bool> _isFormData = new Collection<bool>(); 22 /// <summary> 23 /// 获取文件对应的HttpContent集合,文件如何读取由实际使用方确定,可以ReadAsByteArrayAsync,也可以ReadAsStreamAsync 24 /// </summary> 25 public Collection<HttpContent> FileContents 26 { 27 get 28 { 29 if (this._isFormData.Count != this.Contents.Count)//两者总数不一致,认为未执行过必须的Request.Content.ReadAsMultipartAsync(provider)方法 30 { 31 throw new InvalidOperationException("System.Net.Http.HttpContentMultipartExtensions.ReadAsMultipartAsync must be called first!"); 32 } 33 return new Collection<HttpContent>(this.Contents.Where((ct, idx) => !this._isFormData[idx]).ToList()); 34 } 35 } 36 /// <summary>Gets a <see cref="T:System.Collections.Specialized.NameValueCollection" /> of form data passed as part of the multipart form data.</summary> 37 /// <returns>The <see cref="T:System.Collections.Specialized.NameValueCollection" /> of form data.</returns> 38 public NameValueCollection FormData 39 { 40 get 41 { 42 return this._formData; 43 } 44 } 45 public override async Task ExecutePostProcessingAsync() 46 { 47 for (var i = 0; i < this.Contents.Count; i++) 48 { 49 if (!this._isFormData[i])//非文件 50 { 51 continue; 52 } 53 var formContent = this.Contents[i]; 54 ContentDispositionHeaderValue contentDisposition = formContent.Headers.ContentDisposition; 55 string formFieldName = UnquoteToken(contentDisposition.Name) ?? string.Empty; 56 string formFieldValue = await formContent.ReadAsStringAsync(); 57 this.FormData.Add(formFieldName, formFieldValue); 58 } 59 } 60 public override Stream GetStream(HttpContent parent, HttpContentHeaders headers) 61 { 62 if (parent == null) 63 { 64 throw new ArgumentNullException("parent"); 65 } 66 if (headers == null) 67 { 68 throw new ArgumentNullException("headers"); 69 } 70 ContentDispositionHeaderValue contentDisposition = headers.ContentDisposition; 71 if (contentDisposition == null) 72 { 73 throw new InvalidOperationException("Content-Disposition is null"); 74 } 75 this._isFormData.Add(string.IsNullOrEmpty(contentDisposition.FileName)); 76 return new MemoryStream(); 77 } 78 /// <summary> 79 /// 复制自 System.Net.Http.FormattingUtilities 下同名方法,因为该类为internal,不能在其它命名空间下被调用 80 /// </summary> 81 /// <param name="token"></param> 82 /// <returns></returns> 83 private static string UnquoteToken(string token) 84 { 85 if (string.IsNullOrWhiteSpace(token)) 86 { 87 return token; 88 } 89 if (token.StartsWith(""", StringComparison.Ordinal) && token.EndsWith(""", StringComparison.Ordinal) && token.Length > 1) 90 { 91 return token.Substring(1, token.Length - 2); 92 } 93 return token; 94 } 95 } 96 }