.NET Core 异步文件结果

8
在ASP.Net Core中,返回文件的推荐方法是通过PhysicalFileProvider访问,这提供了额外的安全性,包括将所有路径限定在目录及其子目录中。目前我的整个应用程序都是异步的,我希望所有的方法都保持异步。
public static string BASE_PATH = Path.GetTempPath();
public static string lastSavedFilePath = @"C:\Users\MyUser\AppData\Local\Temp\MyPicture.png"

[HttpGet("{id}")]
public async Task<FileResult> GetFileById(int id)
{
    //provides access to the physical file system, scoping all paths to a directory and its children
    IFileProvider provider = new PhysicalFileProvider(BASE_PATH);
    var fileInfo = provider.GetFileInfo(lastSavedFilePath);
    var fileStream = fileInfo.CreateReadStream();
    this._contentTypeProvider.TryGetContentType(lastSavedFilePath, out var mimeType);
    return File(fileStream, mimeType, "ProfilePicture.png");
}

编辑 原来通过PhysicalFileProvider获得文件不是我想要的异步操作,我真正想要的是读取流的异步操作。

当调用我的文件操作时,如何确保它将异步读取我的流?


我不认为这里有任何好处。我相信,如果特定API的设计需要异步,则应该按照此方式进行设计。如果你仍然想要异步,可以始终使用 Task.Run 进行包装。 - Nkosi
假设您不使用文件提供程序,那么在您的示例中如何“异步”读取该文件(鉴于代码中没有实际读取发生)? - Evk
@Nkosi任务运行会很有益,而纯正常异步运行将释放我的线程,如果有人正在加载100个个人资料图片缩略图,我可能会在访问文件系统的时间内阻塞100个线程,或者我可以在等待获得磁盘访问权限时将它们释放。 - johnny 5
@Evk 哎呀,我真正想要的是异步从流中读取,我会编辑问题。 - johnny 5
1
Evk的回答很准确。 - Nkosi
1个回答

13
PhysicalFileProvider可以完全异步读取文件。 GetFileInfo返回有关文件的信息,这里不需要进行任何异步操作。它类似于new FileInfo("path")CreateReadStream获取目标文件的句柄,类似于File.OpenRead()。同样 - 这里不应该有任何异步操作,而且无论是否使用PhysicalFileProvider都是如此。
当您拥有文件流时,可以像往常一样异步读取它(使用ReadAsync等)。事实上,PhysicalFileProvider.CreateReadStream甚至使用正确的标志(FileOptions.Asynchronous)打开文件,使该流非常适合异步访问(但不适合非异步访问)。
但在您的情况下,您不需要自己读取该文件流。您可以用它直接返回。
return File(fileStream, mimeType, "ProfilePicture.png");

这将会异步地读取并将该文件写入HTTP响应流中。这是因为所有的ActionResult(包括你返回的FileStreamResult)都有一个Task ExecuteAsync方法来执行该结果。ASP.NET将为你执行await yourFileResult.ExecuteAsync(),而该ExecuteAsync方法将以异步方式将文件流复制到HTTP响应中。

简而言之 - 只需使您的签名

public FileResult GetFileById(int id)

你会没事的。应该异步完成的已经在这段代码中异步完成了。


3
@johnny5,正如我在回答中所说的那样,它已经被读取并异步写入响应,您不需要等待任何内容。return File(stream)返回FileStreamResult,在其中ASP.NET会执行await result.ExecuteAsync()。因此,ASP.NET将为您执行该等待操作。 - Evk
啊,好的,那很有道理。你知道有没有文档或源链接可以让我阅读更多并完全了解它的操作方式? - johnny 5
不是很确定...我相信这个文档在某个地方有记录,但我不知道在哪里。我的意思是特别指ActionResult.ExecuteAsync,因为其他的都是常识(我指的是不特定于asp.net core的部分)。 - Evk
谢谢,我会查看HTTP管道文档,我一直想找到它们在哪里处理流。我知道他们这样做,但我想更多地了解它,以便对所有内容有更清晰的了解。 - johnny 5
@johnny5:一切都是开源的,你可以自己查看。ExecuteResultAsync => https://github.com/aspnet/Mvc/blob/rel/2.0.0/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileStreamResultExecutor.cs#L48 => https://github.com/aspnet/Mvc/blob/rel/2.0.0/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileResultExecutorBase.cs#L322 只需要90秒的搜索 :) - Tseng
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接