在Blazor中有没有一种方法可以获取文件流并下载到浏览器?

8

我正在尝试使用 Blazor 进行一些操作,但是我还是新手。我试图获取文件流并下载到浏览器,那么从 Blazor 到浏览器下载文件的最佳方法是什么?

我已经尝试在 Razor 视图中使用返回流的方法,但没有成功。

//In my Blazor view
@code{
    private FileStream Download()
    {
        //get path + file name
        var file = @"c:\path\to\my\file\test.txt";
        var stream = new FileStream(test, FileMode.OpenOrCreate);
        return stream;
    }
}

上面的代码没有给我任何东西,甚至没有错误提示


我理解你的意思是想从服务器下载文件到客户端?还是想上传文件进行处理,比如图片上传? - Zsolt Bendes
我的服务器(A)正在向另一个服务器(B)发送请求以获取文件,然后将其提供给浏览器,至少这是我想让它工作的方式。我正在向另一个资源发出 Web 请求,并希望它触发浏览器下载。 - Abdullah
我的意思是,为什么不让用户直接从服务器(B)下载呢? - Bennyboy1973
3个回答

11

另一个解决方案是使用endpoints.MapControllerRoute添加一个简单的api控制器端点。但这只适用于服务器端的blazor。

例如:

endpoints.MapBlazorHub();
endpoints.MapControllerRoute("mvc", "{controller}/{action}");
endpoints.MapFallbackToPage("/_Host");

然后添加一个控制器。例如:

public class InvoiceController : Controller
{
    [HttpGet("~/invoice/{sessionId}")]
    public async Task<IActionResult> Invoice(string sessionId, CancellationToken cancel)
    {
        return File(...);
    }
}

在 .razor 文件中的用法:

async Task GetInvoice()
{
    ...
    Navigation.NavigateTo($"/invoice/{orderSessionId}", true);
}

1
尽管上述答案在技术上是正确的,但如果您需要传递模型-POST-,则导航管理器将无法工作。在这种情况下,您很可能会使用HttpClient组件。如果是这样,请用DotNetStreamReference实例- new DotNetStreamReference(response.Content)包装响应内容-您的流。这将创建一个ReadableStream。然后使用内容创建Blob。请记住,DotNetStreamReference是在.NET 6 RC1中最近引入的。目前是最有效的方法。否则,您可以使用fetch API并从响应创建Blob。

0
我最终采用了不需要 NavigationManager 的另一种方法。它部分地来自于微软文档这里。在我的情况下,我需要呈现一个 Excel 文件(使用 EPPlus),但这并不重要。我只需要返回一个流以获取我的结果。
在我的 Blazor 页面或组件上,当点击按钮时:
public async Task GenerateFile()
{
  var fileStream = ExcelExportService.GetExcelStream(exportModel);

  using var streamRef = new DotNetStreamReference(stream: fileStream);

  await jsRuntime.InvokeVoidAsync("downloadFileFromStream", "Actual File Name.xlsx", streamRef);
}

GetExcelStream 的代码如下:

public static Stream GetExcelStream(ExportModel exportModel)
{
  var result = new MemoryStream();

  ExcelPackage.LicenseContext = LicenseContext.Commercial;
  var fileName = @$"Gets Overwritten";

  using (var package = new ExcelPackage(fileName))
  {
    var sheet = package.Workbook.Worksheets.Add(exportModel.SomeUsefulName);
    var rowIndex = 1;

    foreach (var dataRow in exportModel.Rows)
    {
      ...
      // Add rows and cells to the worksheet
      ...
    }

    sheet.Cells.AutoFitColumns();

    package.SaveAs(result);
  }

  result.Position = 0; // This is required or no data is in result

  return result;
}

这个 JavaScript 在上面的链接中,但是我在这里添加它作为我唯一需要的东西。

window.downloadFileFromStream = async (fileName, contentStreamReference) => {
  const arrayBuffer = await contentStreamReference.arrayBuffer();
  const blob = new Blob([arrayBuffer]);
  const url = URL.createObjectURL(blob);
  const anchorElement = document.createElement("a");

  anchorElement.href = url;
  anchorElement.download = fileName ?? "";
  anchorElement.click();
  anchorElement.remove();
  URL.revokeObjectURL(url);
}

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