Kummy's Blog

o(︶︿︶)o { name : 'Kummy' , job : 'Feser' }

细谈 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

posted @ 2014-02-21 10:12  李 维  阅读(4315)  评论(4编辑  收藏  举报