我有以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
这可行,并且我的问题是-这是一个好的解决方案吗?我是否需要进一步解决性能问题?
答案 0 :(得分:0)
将文件复制到内存流是一个坏主意。这会减慢整个过程的速度,如果同时进行多次下载,则会使系统的内存超载。
相反,您应该尝试将流从Blob存储“传递”到客户端。我们通常使用FileStreamResult
和blob.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
}