简体   繁体   English

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

[英].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映射到IFormFileFileInfo 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 .我们通常使用FileStreamResultblob.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM