在 ASP.NET 中流式传输大文件上传

Posted

技术标签:

【中文标题】在 ASP.NET 中流式传输大文件上传【英文标题】:Streaming Large File Uploads in ASP.NET 【发布时间】:2012-12-08 05:30:45 【问题描述】:

我有一个 ASP.NET MVC 应用程序,其页面允许用户上传文件。这些文件将有数百兆字节。

我在客户端使用 FineUploader,如果浏览器支持,它将使用 FileAPI/XHR,否则将回退到带有 enctype="multipart whatever" 的 Iframe/form。

所以在服务器端我需要评估Request.Files.Count > 1。如果true,这是一个老式的上传,我会像Request.Files[0].InputStream.CopyTo(myFileStream)一样保存文件,否则我会使用Request.InputStreawm.CopyTo(myFileStream)

这是我编写的一些实际代码:https://github.com/ronnieoverby/file-uploader/blob/master/server/ASP.NET%20MVC%20C%23/FineUpload.cs

这一切都很好,但在我的测试中,我注意到在整个文件上传之前,ASP.NET MVC 控制器操作和 HttpHandler 都不会开始处理,如果文件非常大,这很糟糕,因为这意味着它占用大量 Web 服务器的 RAM。

我发现了这个:Streaming large file uploads to ASP.NET MVC,这听起来很有希望,但我真的不知道代码在他的应用程序中的位置。

那么,问题是:如何在 ASP.NET 中进行上传的同时将上传的文件流式传输到磁盘?

更新

我刚刚看到了一个以前没有深入了解的关键细节。来自HttpPostedFile 文档:

默认情况下,所有请求,包括表单字段和上传的文件, 大于 256 KB 的数据被缓冲到磁盘,而不是保存在服务器中 记忆。

好的,这解决了在大量上传期间网络服务器的 RAM 利用率可能会飙升的担忧。但是,仍然存在一个问题:文件完全传输到 Web 服务器后,服务器必须花时间将其移动到最终目的地。如果文件系统操作是一个副本(如果目标在另一个物理磁盘上则保证),则响应会被不必要地延迟。

老实说,我可以通过增加上传处理程序/操作的响应超时来忍受这种情况。但是,将字节直接流式传输到它们的目的地会很好。

【问题讨论】:

好问题。我以前从未想过这个问题。我不知道这是否与 HTTP 或仅与 ASP.NET 有关。 我认为它与网络服务器有关。某处(现在找不到)我读到有人创建了一个 HttpModule,它将在从请求流式传输时将大型上传文件保存到磁盘,然后将控制权传递给 MVC 操作方法。如果我能做到这一点,那将是圣杯。 @RedFilter 在问题Streaming large file uploads to ASP.NET MVC 中的第二个答案看起来也很有希望。我也会检查一下,以防你错过。 您可以在github.com/maxpavlov/jQuery-File-Upload 找到一个 HttpModule 的大文件上传示例,它是为 bluimp jQuery File Uploader 开发的,但可能很容易适应您的文件上传工具 谢谢,我会检查的。 【参考方案1】:

您可以以完全自定义的方式处理上传,而无需使用缓冲 HttpRequest.GetBufferlessInputStream 方法。基本上,您可以访问原始传入数据,并且可以随意使用它。

我刚刚创建了将原始请求内容保存到文件的小示例:

    创建处理程序:

    public class UploadHandler : IHttpHandler
    
        public void ProcessRequest(HttpContext context)
        
            using (var stream = context.Request.GetBufferlessInputStream())
            using (var fileStream = File.Create("c:\\tempfile.txt"))
            
                stream.CopyTo(fileStream);
            
        
        public bool IsReusable  get   return true;  
    
    

    在 Web.config 中注册:

    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
        <handlers>
            <add name="UploadHandler" verb="POST"
                path="/upload"
                type="UploadHandler"
            resourceType="Unspecified"/>
        </handlers>
    </system.webServer>
    

    使用表单创建页面:

<form action="/upload" method="post" enctype='multipart/form-data'>
     <input type="file" name="aa" id="aa"/>
     <input type="submit"/>
</form>

【讨论】:

@Sergey Zyuzin。谢谢分享代码。但这也将限制在 IIS 的 2gb 限制吧?【参考方案2】:

如果上传和流式传输占用了宝贵的服务器资源,那么您可能想看看在某种云上托管您的媒体文件。 ASP.NET 可以使用 Rackspace,Amazon Cloud API 让您的用户将文件直接上传到 CDN 网络,然后以这种方式提供内容,我知道这并不能回答您的问题,但很多人将会或已经拥有并且以为我会得到我的 2 美分。许多人仍然不选择使用云让我感到惊讶!一旦你去了 CDN,你就再也回不去了。此外,对于大多数 CDN,您还将获得上传容器的流式 URL,它支持许多不同的电影类型,而且它的照明速度很快,不仅让您的用户也可以上传,而且您的网站上的速度也永远不会慢结果。

【讨论】:

我的文件非常敏感,我绝对不能将它们放在 CDN 上。

以上是关于在 ASP.NET 中流式传输大文件上传的主要内容,如果未能解决你的问题,请参考以下文章

asp.net(c#)如何上传大文件?

asp.net(c#)如何上传大文件?

在 ASP.NET Core 1.0 上处理大文件上传

如何在 ASP.Net MVC 4 中上传大文件

在ASP.NET Core 中上传文件

在 ASP.NET Core 3.1 中上传和下载大文件?