多个异步文件上传与分块到ASP.Net Web API

时间:2014-05-07 14:41:00

标签: c# asp.net multithreading asynchronous asp.net-web-api

我已经阅读了许多密切相关的问题,但没有一个能够完全达到这个问题。如果是重复,请发给我一个链接。

我正在使用flowjs库的角度版本来执行HTML5文件上传(https://github.com/flowjs/ng-flow)。这非常有效,我能够以1MB的块同时上传多个文件。有一个ASP.Net Web API文件控制器接受这些并将它们保存在磁盘上。虽然我可以做到这一点,但我并没有有效地做到这一点,并希望了解更好的方法。

首先,我在异步方法中使用了MultipartFormDataStreamProvider,只要在一个块中上传文件就可以正常工作。然后我切换到只使用FileStream将文件写入磁盘。只要块按顺序到达,这也有效,但当然,我不能依赖它。

接下来,为了看到它工作,我将块写入单个文件流并在事后合并它们,因此效率低下。一个1GB的文件将生成一千个上传完成后需要读取和重写的块。我可以将所有文件块保存在内存中,并在它们全部上传后刷新它们,但我担心服务器会爆炸。

似乎应该有一个很好的异步解决方案来解决这个困境,但我不知道它是什么。一种可能性是使用async / await在写入当前块时组合先前的块。另一个可能是使用Begin / EndInvoke来创建一个单独的线程,以便磁盘上的文件操作独立于从HttpContext读取的线程来处理,但这将依赖于{{当我的MVC控制器返回时,我担心创建的线程将被过度终止。我可以创建一个完全独立于ASP.Net运行的ThreadPool,但这将是非常笨拙的。

所以我的问题是,1)是否有一个我想念的简单解决方案? (似乎应该有)和2)如果没有,在Web API框架内解决这个问题的最佳方法是什么?

谢谢,鲍勃

2 个答案:

答案 0 :(得分:9)

我不熟悉那种分块上传,但我相信这应该有效:

  • 当第一个块进入时,使用flowTotalSizepre-allocate the file
  • 每个文件都有一个SemaphoreSlim来序列化该文件的异步写入。
  • 文件中的每个块都将write to its own offsetflowChunkSize * (flowChunkNumber - 1))。

这不会处理意外终止上传的情况。这种解决方案通常涉及分配/写入临时文件(带有特殊扩展名),然后在最后一个块到达后移动/重命名该文件。

不要忘记ensure that your file writing is actually asynchronous

答案 1 :(得分:7)

使用@Stephen Cleary的答案,以及这个帖子:https://github.com/flowjs/ng-flow/issues/41我能够制作一个ASP.NET Web Api实现并上传给那些仍然想知道这个问题的人,比如@Herb Caudill < / p>

https://github.com/samhowes/NgFlowSample/tree/master

原始答案是这个问题的真正答案,但我还没有足够的声誉可以发表评论。我没有使用SemaphoreSlim,而是启用了文件写共享。但实际上是预先分配并确保通过计算偏移量将每个块写入正确的位置。

我将通过以下方式为此流程示例做出贡献:https://github.com/flowjs/flow.js/tree/master/samples