Return 来自 URL 的文件作为 IActionResult

Return File from URL as IActionResult

我正在尝试使用 .Net Core 和 Razor Pages 按下按钮下载 PDF。这和我得到的一样接近,但我遇到了错误

"ObjectDisposedException: Cannot access a closed file. System.IO.FileStream.ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)".

如何正确return文件?

Test.cshtml

@page
@model LoanCalculator.Pages.TestModel
@{
}
<form method="post">
    <fieldset>
        <input type="submit" value="Submit" id="submitButton" />
    </fieldset>
</form>

Test.cshtml.cs

namespace LoanCalculator.Pages
{
    public class TestModel : PageModel
    {

        public void OnGet()
        {
            
        }

    public async Task<IActionResult> OnPostAsync()
    {
        using var httpClient = new HttpClient();

        var url = "https://storage.googleapis.com/a2p-v2-storage/528a02ea-a399-4901-b8d6-d0494be68331";
        byte[] imageBytes = await httpClient.GetByteArrayAsync(url);

        using var fs = new FileStream("favicon.png", FileMode.Create);
        fs.Write(imageBytes, 0, imageBytes.Length);

        return File(fs, "application/pdf", "FileDownloadName.png");
    }
}

问题是您正在处理流而不是将流的位置设置为零。

您可以通过将流从请求移交给响应来提高内存效率。

看看这个例子:

var targetFile = new Uri("https://www.example.com/file.pdf");

var resp = await _httpClientFactory.CreateClient().GetAsync(
    targetFile, HttpCompletionOption.ResponseHeadersRead);

Response.ContentLength = resp.Content.Headers.ContentLength;

return File(await resp.Content.ReadAsStreamAsync(),
    "application/pdf", Path.GetFileName(targetFile.LocalPath));

(这不是凭记忆写的)

此外,您应该使用 IHttpClientFactory 而不是每次都创建一个新的 HttpClient

这方面的一个例子:

// ...
using System.Net.Http;
// ...

namespace LoanCalculator.Pages
{
    public class TestModel : PageModel
    {
        private readonly IHttpClientFactory _httpClientFactory;

        public TestModel(IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
        }
    }
}

在您的 Startup.cs 中添加:

public void ConfigureServices(IServiceCollection services)
{
    // ...
    services.AddHttpClient();
    // ...
}