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


    细谈 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; 
    }
    复制代码

    如果只是上传,简单用是可以的,但是你可能不会发现有什么问题。但如果你在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

    在寂寞的日子里沉淀自己,在程序的日子里找到自己,我为梦想而坚持!
  • 相关阅读:
    正则表达式在行首添加指定内容
    linux之find命令详解
    一次安装rpcbind失败引发的思考
    配置linux实现路由功能
    chkconfig命令详解
    1225 数数字
    蛇形填数 ------- 模拟水题
    开灯问题---------简单模拟
    单源最短路径
    图的表示方式
  • 原文地址:https://www.cnblogs.com/zxtceq/p/6424275.html
Copyright © 2020-2023  润新知