【问题标题】:How does ReadAsMultipartAsync actually work?ReadAsMultipartAsync 如何实际工作?
【发布时间】:2016-08-18 02:27:26
【问题描述】:

我在使用 FormData API 上传的网站中有一个 canvas 元素。这是我的做法:

upload: function (e) {
    var file = this.imagePreview.ui.canvas.get(0).toDataURL("image/jpeg")
                   .replace('data:image/jpeg;base64,', '');
    if (file) {
        var formData = new FormData();
        formData.append('file', file);
        $.ajax({
            url: app.getApiRoot + 'UserFiles/',
            type: "post",
            data: formData,
            processData: false,
            contentType: false,
            error: function () {
                $("#file_upload_result").html('there was an error while submitting');
            }
        });
    }
}

我将按照 this post 替换整个 data:image/jpeg;base64, 业务。

在后端我有以下多部分控制器:

public async Task<IHttpActionResult> PostUserFile()
{
    string imageDir = ConfigurationManager.AppSettings["UploadedImageDir"];
    var PATH = HttpContext.Current.Server.MapPath("~/" + imageDir);
    var rootUrl = Request.RequestUri.AbsoluteUri.Replace(Request.RequestUri.AbsolutePath, String.Empty);

    if (Request.Content.IsMimeMultipartContent())
    {
        var streamProvider = new CustomMultipartFormDataStreamProvider(PATH);
        await Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith(t =>
        {
            if (t.IsFaulted || t.IsCanceled)
            {
                throw new HttpResponseException(HttpStatusCode.InternalServerError);
            }

            var files = streamProvider.FileData.Select(i =>
                        {
                            var info = new FileInfo(i.LocalFileName);
                            return new UserFile(User.Identity.GetUserId(), info.Name, rootUrl + "/" + imageDir + "/" + info.Name, info.Length / 1024);
                        });

            db.UserFiles.AddRange(files);
            db.SaveChangesAsync();
        });

        return Ok();
    }
    else
    {
        throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
    }
}

我在哪里实现CustomMultipartFormDataStreamProvider,如下所示:

public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
    public CustomMultipartFormDataStreamProvider(string path)
        : base(path)
    { }

    public override string GetLocalFileName(Headers.HttpContentHeaders headers)
    {
        var name = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? 
                      headers.ContentDisposition.FileName : 
                      "NoName";
        // This is here because Chrome submits files in quotation 
        // marks which get treated as part of the filename and get escaped
        return name.Replace("\"\"", string.Empty);
    }
}

遗憾的是,streamProvider 上的 FileData 输入到 ReadAsMultipartAsync 方法中是空的:

我觉得有趣的另一件事是上传的二进制文件被转义了,正如我从监视窗口中注意到的那样:

%2f/ 字符的转义序列。

我根本无法查明问题所在。有人有什么建议吗?

【问题讨论】:

    标签: c# asp.net .net asp.net-web-api multipartform-data


    【解决方案1】:

    混合 ContinueWith 和 async/await 会导致问题,只需执行 await Request.Content.ReadAsMultipartAsync(streamProvider); 并且 .ContinueWith 中的所有内容都会像普通代码一样在等待之后进行。

    或者删除 async/await 并添加:

    return Request.Content.ReadAsMultipartAsync(streamProvider).Continu‌​eWith...
    

    你也可以看看这个链接:Sending HTML Form Data in ASP.NET Web API: File Upload and Multipart MIME

    【讨论】:

    • 请详细解释一下答案。
    • 请尝试学习如何使用 Stackoverflow。编辑答案,不要在 cmets 中添加信息。阅读:stackoverflow.com/help/how-to-answer
    • 听起来很合理。让我在今天晚些时候实现它,然后回复您。
    猜你喜欢
    • 2018-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-21
    • 2011-09-27
    • 2021-12-16
    • 2013-03-14
    • 2014-02-21
    相关资源
    最近更新 更多