我正在开发一个文件上传经常发生的应用程序,并且可能非常大。
这些文件正在上传到Web API,然后Web API将从请求中获取流,并将其传递给我的存储服务,然后将其上传到Azure Blob存储。
我需要确保:
我看过this article,它描述了如何禁用输入流缓冲,但是由于许多不同用户的许多文件上传同时发生,因此实际上它实际上是在锡上执行的操作。
这就是我目前控制器中的内容:
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();
}
我不知道如何可靠地测试它。
编辑:我忘了提到直接上传到Blob存储(绕过我的API)是行不通的,因为我正在做一些大小检查(例如,这个用户可以上传500mb吗?有这个用户吗?用过他的配额?)。
答案 0 :(得分:8)
在this Gist的帮助下解决了这个问题。
以下是我如何使用它,以及一个聪明的“黑客”来获取实际的文件大小,而不是先将文件复制到内存中。哦,它的速度是原来的两倍 (显然)。
// Create an instance of our provider.
// See https://gist.github.com/JamesRandall/11088079#file-blobstoragemultipartstreamprovider-cs for implementation.
var provider = new BlobStorageMultipartStreamProvider ();
// This is where the uploading is happening, by writing to the Azure stream
// as the file stream from the request is being read, leaving almost no memory footprint.
await this.Request.Content.ReadAsMultipartAsync(provider);
// We want to know the exact size of the file, but this info is not available to us before
// we've uploaded everything - which has just happened.
// We get the stream from the content (and that stream is the same instance we wrote to).
var stream = await provider.Contents.First().ReadAsStreamAsync();
// Problem: If you try to use stream.Length, you'll get an exception, because BlobWriteStream
// does not support it.
// But this is where we get fancy.
// Position == size, because the file has just been written to it, leaving the
// position at the end of the file.
var sizeInBytes = stream.Position;
Voilá,您获得了上传文件的大小,无需将文件复制到Web实例的内存中。
至于上传文件长度文件,这并不容易,我不得不采用一些非常令人愉快的方法来获得近似值。
在BlobStorageMultipartStreamProvider
:
var approxSize = parent.Headers.ContentLength.Value - parent.Headers.ToString().Length;
这给了我一个非常接近的文件大小,减去几百个字节(取决于我猜的HTTP头)。这对我来说已经足够了,因为我的配额强制执行可以接受削减的几个字节。
只是为了炫耀,这是内存占用,由任务管理器中疯狂准确和高级性能选项卡报告。
答案 1 :(得分:5)