我正在开发一个应用程序,其中文件上传经常发生,并且可以相当大的大小。
这些文件将被上传到Web API,然后Web API将从请求中获取流,并将其传递到我的存储服务,然后存储服务将其上传到Azure Blob存储。
我需要确保:
- 未在Web API示例上写入任何临时文件
- 在将请求流传递给存储服务之前,不会将其完全读入内存(以防止
OutOfMemoryExceptions
)。
我看过this article,它描述了如何禁用输入流缓冲,但是因为来自许多不同用户的许多文件上传同时发生,所以它实际上做到它在tin上所说的是很重要的。
这是我目前控制器中的内容:
if (this.Request.Content.IsMimeMultipartContent())
{
var provider = new MultipartMemoryStreamProvider();
await this.Request.Content.ReadAsMultipartAsync(provider);
var fileContent = provider.Contents.SingleOrDefault();
if (fileContent == null)
{
throw new ArgumentException("No filename.");
}
var fileName = fileContent.Headers.ContentDisposition.FileName.Replace("\"", string.Empty);
// I need to make sure this stream is ready to be processed by
// the Azure client lib, but not buffered fully, to prevent OoM.
var stream = await fileContent.ReadAsStreamAsync();
}
我不知道如何才能可靠地测试这个。
EDIT:我忘了提到直接上传到Blob存储(绕过我的API)不起作用,因为我正在做一些大小检查(例如,此用户可以上传500mb吗?此用户是否已使用其配额?)。
2条答案
按热度按时间ddhy6vgd1#
解决了它,在这个Gist的帮助下。
下面是我如何使用它,沿着一个聪明的“黑客”,以获得实际的文件大小,而不是复制文件到内存第一。哦,它的速度是两倍(显然)。
瞧,你得到了你上传的文件的大小,而不必复制文件到您的web示例的内存.
至于在上传文件之前**获得文件长度,这并不容易,我不得不求助于一些相当不愉快的方法来获得一个近似值。
在
BlobStorageMultipartStreamProvider
中:这给了我一个非常接近的文件大小,减少了几百个字节(我猜取决于HTTP头)。这对我来说已经足够好了,因为我的配额强制可以接受被削减的几个字节。
为了炫耀一下,这里是内存占用量,由任务管理器中的“性能”选项卡报告。
Before -使用MemoryStream,在上传之前将其读入内存
之后-直接写入Blob存储
dldeef672#
我认为更好的方法是从客户端直接访问Azure Blob存储。通过利用Azure存储中的CORS支持,您可以消除Web API服务器上的负载,从而为您的应用程序提供更好的整体可伸缩性。
基本上,你将创建一个共享访问签名(SAS)URL,你的客户端可以使用该URL将文件直接上载到Azure存储。出于安全原因,建议你限制SAS的有效期。有关生成SAS URL的最佳做法指南,请参阅here。
对于您的特定场景,请查看Azure存储团队的this blog,他们讨论了如何使用CORS和SAS来实现此特定场景。此外,还有一个示例应用程序,因此它应该可以为您提供所需的一切。