You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Blazor Server中实现基于当前页面内容的动态文件下载功能

Blazor Server 动态文件下载实现方案

以下两种实现方案均无需单独部署WebAPI项目,可直接运行在单Blazor Server实例中,完美兼容Azure Web App部署,不会出现多进程调试/运行异常问题。

方案一:集成Razor Pages端点(推荐,实现简单)

1. 项目配置

首先在现有Blazor Server项目的Program.cs中开启Razor Pages支持:

// 服务注册阶段添加
builder.Services.AddRazorPages();
// 中间件配置阶段添加,放在MapBlazorHub之前
app.MapRazorPages();

2. 创建下载Razor页面

新增Razor Page(如Pages/DownloadReport.cshtml),对应的PageModel实现逻辑如下:

public class DownloadReportModel : PageModel
{
    // 注入你自己的报表生成服务、分布式缓存
    private readonly IReportGenerator _reportGenerator;
    private readonly IDistributedCache _cache;

    public DownloadReportModel(IReportGenerator reportGenerator, IDistributedCache cache)
    {
        _reportGenerator = reportGenerator;
        _cache = cache;
    }

    public async Task<IActionResult> OnGetAsync(string cacheKey)
    {
        // 从缓存读取Blazor端传入的筛选参数
        var filterJson = await _cache.GetStringAsync(cacheKey);
        if (string.IsNullOrEmpty(filterJson)) return NotFound("参数已过期");
        
        var filterParams = JsonSerializer.Deserialize<ReportFilterParams>(filterJson);
        // 生成报表字节内容
        byte[] reportBytes = await _reportGenerator.GenerateAsync(filterParams);
        
        // 返回文件结果,第二个参数对应MIME类型,第三个为下载默认文件名
        return File(reportBytes, 
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 
            $"报表_{DateTime.Now:yyyyMMddHHmmss}.xlsx");
    }
}

如果你的筛选参数很少(比如只有2-3个简单字段),可以直接用查询字符串传递,无需缓存,直接在OnGet方法中接收对应参数即可。

3. Blazor端触发下载

Blazor组件中,首先在wwwroot/js/common.js中加入极简的下载触发JS:

function triggerDownload(downloadUrl) {
    const tempLink = document.createElement('a');
    tempLink.href = downloadUrl;
    tempLink.target = '_blank';
    document.body.appendChild(tempLink);
    tempLink.click();
    document.body.removeChild(tempLink);
}

在_Layout.cshtml中引入该JS文件,然后在报表页面的组件中实现下载逻辑:

@inject IJSRuntime JSRuntime
@inject IDistributedCache Cache

<!-- 页面其他内容 -->
<button @onclick="HandleDownloadReport">下载当前报表</button>

@code {
    // 当前页面用户选择的筛选条件
    private ReportFilterParams _currentFilter = new();

    private async Task HandleDownloadReport()
    {
        // 生成唯一缓存键,将筛选参数存入缓存,设置1分钟过期
        var cacheKey = Guid.NewGuid().ToString("N");
        await _cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(_currentFilter), 
            new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1) });
        
        // 调用JS触发下载
        await JSRuntime.InvokeVoidAsync("triggerDownload", $"/DownloadReport?cacheKey={cacheKey}");
    }
}

方案二:集成内置API控制器

Blazor Server项目本身支持直接添加API控制器,无需创建单独的WebAPI项目:

1. 项目配置

在Program.cs中开启控制器支持:

// 服务注册阶段添加
builder.Services.AddControllers();
// 中间件配置阶段添加,放在MapBlazorHub之前
app.MapControllers();

2. 新增报表下载控制器

[ApiController]
[Route("api/report")]
public class ReportController : ControllerBase
{
    private readonly IReportGenerator _reportGenerator;

    public ReportController(IReportGenerator reportGenerator)
    {
        _reportGenerator = reportGenerator;
    }

    [HttpPost("download")]
    public async Task<IActionResult> Download([FromBody] ReportFilterParams filterParams)
    {
        byte[] reportBytes = await _reportGenerator.GenerateAsync(filterParams);
        return File(reportBytes, "application/pdf", $"报表_{DateTime.Now:yyyyMMddHHmmss}.pdf");
    }
}

3. Blazor端调用接口下载

添加JS方法:

async function postDownload(url, params) {
    const res = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(params)
    });
    const blob = await res.blob();
    const downloadUrl = URL.createObjectURL(blob);
    const tempLink = document.createElement('a');
    tempLink.href = downloadUrl;
    tempLink.download = '报表.pdf';
    tempLink.click();
    URL.revokeObjectURL(downloadUrl);
}

Blazor端调用:

private async Task HandleDownloadReport()
{
    await JSRuntime.InvokeVoidAsync("postDownload", "/api/report/download", _currentFilter);
}

注意事项

  • 两种方案都属于单项目实现,所有服务、配置可以和Blazor Server共享,部署到Azure Web App时只需要发布一个包,没有多项目部署的问题
  • 不需要单独创建WebAPI项目,避免了多进程调试、跨域、部署复杂度高的问题
  • 如果报表文件体积较大,建议在生成文件时使用流式返回,减少内存占用

内容的提问来源于stack exchange,提问作者Tessaract

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 08:36:03