C# 如何在没有临时文件的情况下将流从Web API传递到Azure Blob存储?

C# 如何在没有临时文件的情况下将流从Web API传递到Azure Blob存储?,c#,asp.net,azure,asp.net-web-api,azure-storage,C#,Asp.net,Azure,Asp.net Web Api,Azure Storage,我正在开发一个文件上传经常发生的应用程序,它的大小可能相当大 这些文件正在上载到Web API,然后Web API将从请求中获取流,并将其传递到我的存储服务,然后将其上载到Azure Blob存储 我需要确保: 没有临时工。文件写在Web API实例上 在将请求流传递到存储服务之前,请求流没有完全读入内存(以防止内存不足异常) 我已经看过了,它描述了如何禁用输入流缓冲,但是由于来自许多不同用户的许多文件上载同时发生,所以它实际上按照tin上的说明执行是很重要的 这是我目前在控制器中的配置:

我正在开发一个文件上传经常发生的应用程序,它的大小可能相当大

这些文件正在上载到Web API,然后Web API将从请求中获取流,并将其传递到我的存储服务,然后将其上载到Azure Blob存储

我需要确保:

  • 没有临时工。文件写在Web API实例上
  • 在将请求流传递到存储服务之前,请求流没有完全读入内存(以防止内存不足异常)
我已经看过了,它描述了如何禁用输入流缓冲,但是由于来自许多不同用户的许多文件上载同时发生,所以它实际上按照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();
}
我不知道怎样才能可靠地测试这个


编辑:我忘了提到直接上传到Blob存储(绕过我的API)不起作用,因为我正在进行一些大小检查(例如,该用户可以上传500mb吗?该用户是否使用了他的配额?)。

我认为更好的方法是您直接从客户端转到Azure Blob存储。通过利用Azure存储中的CORS支持,您消除了Web API服务器上的负载,从而提高了应用程序的总体规模

基本上,您将创建一个共享访问签名(SAS)URL,您的客户端可以使用该URL将文件直接上载到Azure存储。出于安全原因,建议您限制SAS的有效时间段。提供了生成SAS URL的最佳实践指南


有关您的特定场景,请查看Azure存储团队,他们在那里讨论了在这个特定场景中使用CORS和SAS。还有一个示例应用程序,因此它将为您提供所需的一切。

在的帮助下解决了它

下面是我如何使用它,以及一个聪明的“黑客”来获得实际的文件大小,而无需先将文件复制到内存中。哦,而且速度是原来的两倍 (显然)

瞧,您获得了上载文件的大小,而不必将文件复制到web实例的内存中

至于在上传文件之前获取文件长度,这并不容易,我不得不求助于一些不太令人愉快的方法来获得近似值

BlobStorageMultipartStreamProvider
中:

var approxSize = parent.Headers.ContentLength.Value - parent.Headers.ToString().Length;
这使我的文件大小非常接近,减少了几百字节(我想这取决于HTTP头)。这对我来说已经足够好了,因为我的配额强制执行可以接受减少几个字节

为了炫耀一下,这里是内存占用,由Task Manager中的“极其精确和高级性能”选项卡报告

Before-使用MemoryStream,在上传之前将其读入内存

后-直接写入Blob存储

您是否尝试过将输入流直接复制到blob存储?这就是我正在做的,但我需要确保在blob存储客户端开始上传之前,我没有完全缓冲输入流,我不知道如何测试它是否真的发生了。你是否尝试过分析你的应用程序,以查看它是否在读取前缓冲?获取一个文件并测试你的应用程序。我发现该文件在发送到Azure之前确实已复制到内存中。这是一个问题。您仍然可以使用此解决方案。在生成SAS URL的方法中,您还可以返回为用户维护的任何数据配额,例如剩余存储量。在JavaScript中,添加一些逻辑以查看您的字节数组是否大于您为用户返回的配额,如果大于,则在客户端上显示错误。这是一个问题,因为第三方将与我的API集成,因此没有任何东西可以阻止他们忽略配额。永远不要相信客户。:)是的,但是你不需要为此承担任何摄入成本,而且存储成本非常便宜。所以,我建议也在服务器端验证它。我不能在服务器端验证它,因为流没有接触到我的服务器。另一件事是,我将文件的“引用”存储在SQL数据库中。它必须通过我的服务器。我正在考虑一个后台工作来完成这项工作。在某些地方,您已经在这样做了,因为您知道用户的配额是多少。您可以在用户每次上载文件以启动检查用户配额的作业时将消息放入队列。不管怎样,我只想考虑一些想法。
var approxSize = parent.Headers.ContentLength.Value - parent.Headers.ToString().Length;