代码之家  ›  专栏  ›  技术社区  ›  Benjamin Pollack Stefan Rusek

流式大文件上载到ASP.NET MVC

  •  56
  • Benjamin Pollack Stefan Rusek  · 技术社区  · 17 年前

    对于我正在开发的应用程序,我需要允许用户通过我们的网站上传非常大的文件——也就是说,可能有很多GB。不幸的是,ASP.NET MVC似乎在开始服务之前将整个请求加载到RAM中——这对于这样的应用程序来说并不理想。值得注意的是,试图通过以下代码规避此问题:

    if (request.Method == "POST")
    {
        request.ContentLength = clientRequest.InputStream.Length;
        var rgbBody = new byte[32768];
    
        using (var requestStream = request.GetRequestStream())
        {
            int cbRead;
            while ((cbRead = clientRequest.InputStream.Read(rgbBody, 0, rgbBody.Length)) > 0)
            {
                fileStream.Write(rgbBody, 0, cbRead);
            }
        }
    }
    

    2 回复  |  直到 17 年前
        1
  •  25
  •   Benjamin Pollack Stefan Rusek    16 年前

    结果证明我最初的代码基本上是正确的;唯一需要的改变就是改变

    request.ContentLength = clientRequest.InputStream.Length;
    

    request.ContentLength = clientRequest.ContentLength;
    

    前一个流在整个请求中确定内容长度;后者只是检查 Content-Length 标头,它只要求已完整发送标头。这允许IIS几乎立即开始流式处理请求,从而完全消除了原始问题。

        2
  •  17
  •   D'Arcy Rittich    17 年前

    当然,你能做到。看见 RESTful file uploads with HttpWebRequest and IHttpHandler . 我已经使用这种方法好几年了,有一个网站已经用至少几GB的文件进行了测试。本质上,您希望创建自己的IHttpHandler,这比听起来容易。

    接口,这意味着您必须支持IsReusable属性和ProcessRequest方法。最重要的是,您的web.config有一个小小的改变,它就像一个魅力。在请求生命周期的这个阶段,上传的整个文件不会加载到内存中,因此它会巧妙地解决内存不足的问题。

    请注意,在web.config中,

    <httpHandlers>
     <add verb="*" path="DocumentUploadService.upl" validate="false" type="TestUploadService.FileUploadHandler, TestUploadService"/>
    </httpHandlers>
    

    引用的文件DocumentUploadService.upl实际上不存在。这只是为了提供一个备用扩展,以便标准处理程序不会拦截请求。您将文件上载表单指向该路径,但随后您的FileUploadHandler类将启动并实际接收文件。

    更新: HttpPostedFile 类,其中

    if (context.Request.Files.Count > 0)
    {
        string tempFile = context.Request.PhysicalApplicationPath;
        for(int i = 0; i < context.Request.Files.Count; i++)
        {
            HttpPostedFile uploadFile = context.Request.Files[i];
            if (uploadFile.ContentLength > 0)
            {
                uploadFile.SaveAs(string.Format("{0}{1}{2}",
                  tempFile,"Upload\\", uploadFile.FileName));
            }
        }
    }