细谈 Web Api 图片上传,在使用 Task.ContinueWith 变量无法赋值问题的解决办法!

来源:互联网 发布:c语言printf输出汉字 编辑:程序博客网 时间:2024/05/28 14:56

在使用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

0 0