.NET:如何将Azure RetriableStreamImpl转换为ASP.Net Core IFormFile?

时间:2020-06-15 10:18:09

标签: .net azure asp.net-core stream

我有以blob形式存储在Azure存储中的文件,每个文件一个blob。文件大小最多可以达到100MB。

我正在实现一个API,将这些文件作为ASP.Net Core 3.1 IFormFile接口的实例提供给使用者。

在API的服务器端实现中,我正在使用Azure的BlobClient.DownloadAsync()方法下载文件。这将返回BlobDownloadInfo的实例,其中包含我需要的所有数据。具体来说,可通过BlobDownloadInfo.Value.Content属性使文件内容可用,该属性在运行时包含RetriableStreamImpl

的实例。

我正在使用默认实现BlobDownaldInfo类从IFormFile映射到FileInfo,如下所示:

BlobDownloadInfo response = await blobClient.DownloadAsync();

IFormFile file = new FormFile(
    response.Value.Content, 
    0, // baseStreamOffset
    response.Value.ContentLength, 
    "foo", 
    "bar.txt")
{
    Headers = new HeaderDictionary(),
    ContentType = response.Value.ContentType,
    ContentDisposition = response.Value.Details.ContentDisposition
};

不幸的是,这段代码抛出:

System.NotSupportedException : Specified method is not supported.
   at Azure.Core.Pipeline.RetriableStream.RetriableStreamImpl.set_Position(Int64 value)

在我看来,FormFile构造函数正在尝试将流Position设置为0,但该流是RetriableStreamImpl,不允许设置其{{1} }属性。

我通过将Position内容复制到RetriableStreamImpl并将其传递到MemoryStream构造函数中来解决此问题:

FormFile

这可行,并且我的问题是-这是一个好的解决方案吗?我是否需要进一步解决性能问题?

1 个答案:

答案 0 :(得分:0)

将文件复制到内存流是一个坏主意。这会减慢整个过程的速度,如果同时进行多次下载,则会使系统的内存超载。

相反,您应该尝试将流从Blob存储“传递”到客户端。我们通常使用FileStreamResultblob.OpenReadAsync进行此操作。 blobClient.DownloadAsync对我来说很好,因此您可以尝试将IFile替换为FileStreamResult

一些入门代码:

var blob = container.GetBlockBlobReference(path);
var stream = blob.OpenReadAsync(cancellationToken);

// ...

// Controller action:
return new FileStreamResult(stream, contentType)
 {
     FileDownloadName = "myfile.txt" // => ContentDisposition Header
 }