在使用Asp.Net Web Api 圖片上傳接口的時候,到網上找了一些個例子,但大多數找到都是這個版本!
[HttpPost] public Task<Hashtable> ImgUpload() { // 檢查是否是 multipart/form-data if (!Request.Content.IsMimeMultipartContent("form-data")) throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); //文件保存目錄路徑 string SaveTempPath = "~/SayPlaces/" + "/SayPic/SayPicTemp/"; String dirTempPath = HttpContext.Current.Server.MapPath(SaveTempPath); // 設置上傳目錄 var provider = new MultipartFormDataStreamProvider(dirTempPath); //var queryp = Request.GetQueryNameValuePairs();//獲得查詢字符串的鍵值集合 var task = Request.Content.ReadAsMultipartAsync(provider). ContinueWith<Hashtable>(o => { Hashtable hash = new Hashtable(); hash["error"] = 1; hash["errmsg"] = "上傳出錯"; var file = provider.FileData[0];//provider.FormData string orfilename = file.Headers.ContentDisposition.FileName.TrimStart('"').TrimEnd('"'); FileInfo fileinfo = new FileInfo(file.LocalFileName); //最大文件大小 int maxSize = 10000000; if (fileinfo.Length <= 0) { hash["error"] = 1; hash["errmsg"] = "請選擇上傳文件。"; } else if (fileinfo.Length > maxSize) { hash["error"] = 1; hash["errmsg"] = "上傳文件大小超過限制。"; } else { string fileExt = orfilename.Substring(orfilename.LastIndexOf('.')); //定義允許上傳的文件擴展名 String fileTypes = "gif,jpg,jpeg,png,bmp"; if (String.IsNullOrEmpty(fileExt) || Array.IndexOf(fileTypes.Split(','), fileExt.Substring(1).ToLower()) == -1) { hash["error"] = 1; hash["errmsg"] = "上傳文件擴展名是不允許的擴展名。"; } else { String ymd = DateTime.Now.ToString("yyyyMMdd", System.Globalization.DateTimeFormatInfo.InvariantInfo); String newFileName = DateTime.Now.ToString("yyyyMMddHHmmss_ffff", System.Globalization.DateTimeFormatInfo.InvariantInfo); fileinfo.CopyTo(Path.Combine(dirTempPath, newFileName + fileExt), true); fileinfo.Delete(); hash["error"] = 0; hash["errmsg"] = "上傳成功"; } } return hash; }); return task; }
如果只是上傳,簡單用是可以的,但是你可能不會發現有什么問題。但如果你在 Request.Content.ReadAsMultipartAsync(provider).ContinueWith 延時Task任務 里面賦值一個變量,你就會發現 始終賦值不上,不信你可以試試。
例子 如下:
public string UploadFile() { if (Request.Content.IsMimeMultipartContent()) { //Save file MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(HttpContext.Current.Server.MapPath("~/Files"));string filename = "Not set"; Request.Content.ReadAsMultipartAsync(provider).ContinueWith(o => { //File name filename = "Set success"; }, TaskScheduler.FromCurrentSynchronizationContext()); return filename; } else { return "Invalid."; } }
上面的得出的結果: filename = "Not set" ;
【注意如下結論】
經測試發現如下結論,在執行 Request.Content.ReadAsMultipartAsync(provider).ContinueWith 異步延時任務的時候,先不會被立即執行。
等待 return 結束之后才會被執行。這也就是為什么返回的總是: "Not set" 。
經過幾天的摸索測試,在StackOverFlow上找到了一個解決的辦法如下:
IEnumerable<HttpContent> parts = null; Task.Factory .StartNew(() => parts = Request.Content.ReadAsMultipartAsync().Result.Contents, CancellationToken.None, TaskCreationOptions.LongRunning, // guarantees separate thread TaskScheduler.Default) .Wait();
改造后就變成了這樣,真的太棒了!
public string UploadFile() { if (Request.Content.IsMimeMultipartContent()) { //Save file MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(HttpContext.Current.Server.MapPath("/UploadUser/")); string filename = "Not set"; IEnumerable<HttpContent> parts = null; Task.Factory .StartNew(() => { parts = Request.Content.ReadAsMultipartAsync(provider).Result.Contents; filename = "Set Success"; }, CancellationToken.None, TaskCreationOptions.LongRunning, // guarantees separate thread TaskScheduler.Default) .Wait(); return filename; } else { return "Invalid."; } }
相關Task的文章:
http://stackoverflow.com/questions/10502353/task-continuewith-execution-orderTa
http://www.strathweb.com/2012/08/a-guide-to-asynchronous-file-uploads-in-asp-net-web-api-rtm/
StackOverFlow 最終解決方案:
http://stackoverflow.com/questions/15201255/request-content-readasmultipartasync-never-returns
