細談 Web Api 圖片上傳,在使用 Task.ContinueWith 變量無法賦值問題的解決辦法!


在使用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; 
}
View Code

 

如果只是上傳,簡單用是可以的,但是你可能不會發現有什么問題。但如果你在 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM