[英].NET: How to convert an Azure RetriableStreamImpl into an ASP.Net Core IFormFile?
I have files stored in Azure Storage in the form of blobs, one blob per file.我有文件以 blob 的形式存储在 Azure Storage 中,每个文件一个 blob。 Files sizes can go up to ~100MB in size.
文件大小可以 go 最大 ~100MB。
I am implementing an API that serves these files to consumers as instance of ASP.Net Core 3.1's IFormFile
interface.我正在实现一个 API,它将这些文件作为 ASP.Net Core 3.1 的
IFormFile
接口的实例提供给消费者。
In my server-side implementation of the API I am downloading the files using Azure's BlobClient.DownloadAsync()
method.在 API 的服务器端实现中,我正在使用 Azure 的
BlobClient.DownloadAsync()
方法下载文件。 This returns an instance of BlobDownloadInfo
that contains all the data that I need.这将返回一个
BlobDownloadInfo
实例,其中包含我需要的所有数据。 Specifically, the file's content are made available through the BlobDownloadInfo.Value.Content
property which, at runtime, contains an instance of RetriableStreamImpl
具体来说,文件的内容通过
BlobDownloadInfo.Value.Content
属性提供,该属性在运行时包含RetriableStreamImpl
的实例
I am mapping from the BlobDownaldInfo
into an IFormFile
using the default implementation, FileInfo
class like so:我使用默认实现从
BlobDownaldInfo
映射到IFormFile
, FileInfo
class 如下所示:
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
};
Unfortunately for me, this code throws:对我来说不幸的是,这段代码抛出:
System.NotSupportedException: Specified method is not supported. at Azure.Core.Pipeline.RetriableStream.RetriableStreamImpl.set_Position(Int64 value)
It looks to me as though the FormFile
constructor is trying to set the stream Position
to 0 but that that stream is an RetriableStreamImpl
which does not allow setting its Position
property. It looks to me as though the
FormFile
constructor is trying to set the stream Position
to 0 but that that stream is an RetriableStreamImpl
which does not allow setting its Position
property.
I've worked around this issue by copying the RetriableStreamImpl
contents into a MemoryStream
and passing that into the FormFile
constructor:我通过将
RetriableStreamImpl
内容复制到MemoryStream
并将其传递给FormFile
构造函数来解决此问题:
var memoryStream = new MemoryStream();
response.Value.Content.CopyTo(memoryStream);
This works and my question is - Is this a good solution?这行得通,我的问题是- 这是一个好的解决方案吗? Are there any performance issues I need to address further?
我需要进一步解决任何性能问题吗?
Copying the file to a memory stream is a bad idea.将文件复制到 memory stream 是个坏主意。 It will slow down the whole process and if many downloads are happening at the same time, you will overload your system's memory.
它会减慢整个过程,如果同时发生许多下载,您的系统 memory 将会过载。
Instead, you should try to "pass through" the stream from blob storage to the client.相反,您应该尝试将 stream 从 blob 存储“传递”到客户端。 We usually do this using
FileStreamResult
and blob.OpenReadAsync
.我们通常使用
FileStreamResult
和blob.OpenReadAsync
来做到这一点。 blobClient.DownloadAsync
looks fine for me, so you could try replacing IFile
with FileStreamResult
. blobClient.DownloadAsync
对我来说看起来不错,因此您可以尝试将IFile
替换为FileStreamResult
。
Some code to get you started:一些可以帮助您入门的代码:
var blob = container.GetBlockBlobReference(path);
var stream = blob.OpenReadAsync(cancellationToken);
// ...
// Controller action:
return new FileStreamResult(stream, contentType)
{
FileDownloadName = "myfile.txt" // => ContentDisposition Header
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.