【问题标题】:Error with ReadAsMultipartAsync and MultiPartFormDataStreamProviderReadAsMultipartAsync 和 MultiPartFormDataStreamProvider 出错
【发布时间】:2015-02-20 21:16:12
【问题描述】:

我正在尝试将文件异步上传到我的 Web 服务器 (ASP.NET MVC)。专门针对我的 web api 端点。我遵循了几个教程,但我不断收到空参数错误。

当我继承 MultipartFormDataStreamProvider 时会发生这种情况。 GetLocalFileName 方法首先被正确调用,使用正确的 HttpContentHeaders,然后第二次使用 null 标头调用。

使用我设置的文件名成功保存了文件,但是当我遇到异常时,我无法知道生成的名称是什么。

但是,如果我只使用基本 MultipartFormDataStreamProvider 类,文件将完美保存,没有错误,但在这种情况下我无法控制文件名。

这是api方法:

[HttpPost]
    public async Task<FilesUploadResult> Save()
    {
        // Check if the request contains multipart/form-data.
        if (!Request.Content.IsMimeMultipartContent())
        {
            var ret = new FilesUploadResult(HttpStatusCode.UnsupportedMediaType, null);
            ret.Message = "Unsupported Media Type. Request must contain multipart/form-data form.";
            return ret;
        }

        var path = UploadsFolderPath;

        // to-do: this works but for some reason makes a call with empty headers.
        var provider = new SimpleMultipartFormDataStreamProvider(path);

        // this provider saves the file with an arbritrary name
        //var provider = new MultipartFormDataStreamProvider(path);

        try
        {
            // Read the form data.
            await Request.Content.ReadAsMultipartAsync(provider as MultipartFormDataStreamProvider);

            var files = from f in provider.FileData
                        let info = new FileInfo(f.LocalFileName)
                        select new FileUploadDescription(info.Name, path + "\\" + info.Name, info.Length, HttpStatusCode.Created);

            var ret = new FilesUploadResult(HttpStatusCode.OK, files);
            return ret;
        }
        catch (Exception ex)
        {
            var ret = new FilesUploadResult(HttpStatusCode.InternalServerError, null);
            ret.Message = ex.Message;
            return ret;
        }
    }

这是我SimpleMultipartFormDataStreamProvider的代码:

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

    public override string GetLocalFileName(HttpContentHeaders headers)
    {

        // make sure the headers are valid
        if (headers == null)
        {

            throw new ArgumentNullException("headers");
        }

        // filename
        var filename = CleanString(headers.ContentDisposition.FileName); ;

        // create the local file name
        var localFileName = string.Format("_{0}_{1}", GetRandomName(), filename);

        //this is here because Chrome submits files in quotation marks which get treated as part of the filename and get escaped
        return localFileName.Replace("\"", string.Empty);
    }

    private string GetRandomName()
    {
        return GuidHelper.ShortUniqueId(16);
    }

    private static string CleanString(string str)
    {
        if (string.IsNullOrWhiteSpace(str))
            return string.Empty;

        var sb = new StringBuilder();
        foreach (char c in str)
        {
            if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '.' || c == '_')
            {
                sb.Append(c);
            }
        }
        return sb.ToString();
    }
}

谁能告诉我为什么我两次调用GetLocalFileName,而第二次调用空标题?

【问题讨论】:

    标签: c# .net asp.net-mvc async-await asp.net-web-api


    【解决方案1】:

    即使我在 MVC4 中遇到过这种行为,它也会提交 2 个文件,其中一个是空的,所以最好检查文件是否有任何内容,然后继续保存文件。 可以有多种方法: 其中之一是从Request.Files 获取所有文件的列表(这是一个字符串数组)

          foreach (string fileName in Request.Files)
                {
                    HttpPostedFileBase file = Request.Files[fileName];
                    //Save file content goes here
                    if (file != null && file.ContentLength > 0)
                     {
                         //logic to save the content
                     }
                 }
    

    【讨论】:

    • 感谢您的回答@nikitech-kolpe,但我也不确定您指的是什么 Request 对象。在我的 WebApi 控制器中,我的 Request 对象没有任何名为 Files 的属性。还有什么我可能遗漏的吗?
    【解决方案2】:

    GetLocalFileName 为多部分请求中的每个文件调用一次。如果您在同一个请求中发送两个文件,GetLocalFileName 将被调用两次。我认为您应该检查您如何调用该服务并使用fiddler 或类似的东西来查看您是否真的在发送两个文件。如果您在同一个请求中发送多个部分,请尝试指定每个部分的 ContentType。

    【讨论】:

    • 我会注意这一点,但我认为这不是问题,因为当我使用默认的 MultipartFormDataStreamProvider 时,我没有收到任何错误,它只保存一个文件。
    【解决方案3】:

    我自己想出来的。

    问题是我为子类化 MultipartDataStreamProvider 而实现的类在不同的项目中。

    该项目对 .Net .Http 程序集的引用与当前 Web Api 项目中的不同。

    我唯一做的就是将 CustomMultipartDataStreamProvider 类移到同一个项目中,一切都运行良好。

    【讨论】:

    • 这对我来说是个问题。让我把头发拉了一个下午。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2013-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 1970-01-01
    • 1970-01-01
    • 2018-12-21
    相关资源
    最近更新 更多