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

ASP.NET Core 3.1 MVC如何直接下载控制器返回的视图为PDF

在ASP.NET Core 3.1 MVC中实现视图直接下载为PDF

问题背景

点击下载按钮提交表单时,会调用以下控制器方法:

public async Task<IActionResult> InvigilatorDiaryPrint(InvigilatorDiaryDTO invigilatorDiaryDTO)
{
    var status = this._invigilatorDiaryService.CreateInvigilatorDiaryEntry(invigilatorDiaryDTO);

    if (invigilatorDiaryDTO.StudentDetails.Count == 0 && status)
    {
        invigilatorDiaryDTO = await this._invigilatorDiaryService.GetStudentEntryDetails(invigilatorDiaryDTO);
    }

    return this.View("~/Views/InvigilatorDiary/InvigilatorDiaryPrint.cshtml", invigilatorDiaryDTO);
}

当前该方法会直接展示InvigilatorDiaryPrint.cshtml视图,需求改为点击下载时直接将该视图内容生成PDF并触发下载,而非展示视图。

实现步骤

1. 安装视图转PDF依赖包

使用适用于.NET Core的DinkToPdf库,通过NuGet命令安装:

Install-Package DinkToPdf

同时根据系统架构(x86/x64)下载对应版本的wkhtmltopdf二进制文件,将其放在项目的wwwroot/wkhtmltopdf目录下(可自定义路径)。

2. 配置服务(Startup.cs)

在ConfigureServices中注册PDF转换服务:

using DinkToPdf;
using DinkToPdf.Contracts;
using System.Reflection;

public void ConfigureServices(IServiceCollection services)
{
    // 其他服务配置...
    var loadContext = new CustomAssemblyLoadContext();
    // 替换为你存放wkhtmltox.dll的实际路径
    loadContext.LoadUnmanagedLibrary(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "wkhtmltopdf", "x64", "wkhtmltox.dll"));
    services.AddSingleton<IConverter>(new SynchronizedConverter(new PdfTools()));
}

// 自定义加载上下文类,用于加载非托管库
public class CustomAssemblyLoadContext : AssemblyLoadContext
{
    public IntPtr LoadUnmanagedLibrary(string absolutePath)
    {
        return LoadUnmanagedDll(absolutePath);
    }
}

3. 修改控制器方法,实现视图转PDF下载

先添加一个辅助方法,用于将视图渲染为HTML字符串:

private async Task<string> RenderViewToStringAsync(string viewName, object model)
{
    var httpContext = new DefaultHttpContext { RequestServices = HttpContext.RequestServices };
    var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

    using var sw = new StringWriter();
    var viewResult = ViewEngines.Engines.FindView(actionContext, viewName, false);
    if (viewResult.View == null)
    {
        throw new ArgumentNullException($"{viewName} 视图不存在");
    }

    var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
    {
        Model = model
    };

    var viewContext = new ViewContext(
        actionContext,
        viewResult.View,
        viewData,
        new TempDataDictionary(actionContext.HttpContext, TempDataProvider),
        sw,
        new HtmlHelperOptions()
    );

    await viewResult.View.RenderAsync(viewContext);
    return sw.ToString();
}

然后修改原控制器方法,将视图转为PDF并返回下载文件:

private readonly IConverter _pdfConverter;

// 通过构造函数注入PDF转换服务
public YourControllerName(IConverter pdfConverter)
{
    _pdfConverter = pdfConverter;
}

public async Task<IActionResult> InvigilatorDiaryPrint(InvigilatorDiaryDTO invigilatorDiaryDTO)
{
    var status = this._invigilatorDiaryService.CreateInvigilatorDiaryEntry(invigilatorDiaryDTO);

    if (invigilatorDiaryDTO.StudentDetails.Count == 0 && status)
    {
        invigilatorDiaryDTO = await this._invigilatorDiaryService.GetStudentEntryDetails(invigilatorDiaryDTO);
    }

    // 把目标视图渲染成HTML字符串
    var htmlContent = await RenderViewToStringAsync("~/Views/InvigilatorDiary/InvigilatorDiaryPrint.cshtml", invigilatorDiaryDTO);

    // 配置PDF生成参数
    var pdfConfig = new HtmlToPdfDocument()
    {
        GlobalSettings = new GlobalSettings()
        {
            ColorMode = ColorMode.Color,
            Orientation = Orientation.Portrait,
            PaperSize = PaperKind.A4,
            Margins = new MarginSettings { Top = 15, Bottom = 15, Left = 10, Right = 10 }
        },
        Objects = {
            new ObjectSettings() {
                HtmlContent = htmlContent,
                WebSettings = { DefaultEncoding = "utf-8", UserStyleSheet = Url.Content("~/css/pdf-style.css") },
                HeaderSettings = { FontSize = 10, Right = "页码 [page]/[toPage]", Line = true },
                FooterSettings = { FontSize = 10, Center = $"生成时间: {DateTime.Now:yyyy-MM-dd HH:mm}" }
            }
        }
    };

    // 生成PDF字节数组
    var pdfBytes = _pdfConverter.Convert(pdfConfig);

    // 返回PDF文件,触发浏览器下载
    return File(pdfBytes, "application/pdf", $"监考日志_{DateTime.Now:yyyyMMddHHmmss}.pdf");
}

4. 注意事项

  • 视图中引用的CSS、图片资源需使用绝对路径(可通过Url.Content生成),否则PDF中可能无法正常加载样式和图片。
  • 不同操作系统需要对应版本的wkhtmltopdf二进制文件,部署时需注意匹配服务器架构。
  • 复杂视图可能需要调整PDF参数(如页面方向、边距)以适配内容显示。

内容的提问来源于stack exchange,提问作者Athulya P D

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:27:31