在 ASP .NET Core中通过 Web API 中将 HTML 转换为 PDF

作者:微信公众号:【架构师老卢】
6-23 14:36
40

概述:生成 PDF 文档是 Web 应用程序中的常见要求,无论是发票、报告还是其他可打印内容。在本文中,我们将学习如何使用 PuppeteerSharp(流行的 Puppeteer 库的 .NET 端口)在 ASP .NET Core Web API 中将 HTML 转换为 PDF。创建新的 Web API 项目打开 Visual Studio 并创建新的 ASP .NET Core Web API 项目。设置项目名称和位置,并将框架设置为 .NET 8。安装 PuppeteerSharp 库打开 Nuget 包管理器,搜索并安装 PuppeteerSharp 包。创建 HtmlToPdfServi

生成 PDF 文档是 Web 应用程序中的常见要求,无论是发票、报告还是其他可打印内容。在本文中,我们将学习如何使用 PuppeteerSharp(流行的 Puppeteer 库的 .NET 端口)在 ASP .NET Core Web API 中将 HTML 转换为 PDF。

创建新的 Web API 项目

打开 Visual Studio 并创建新的 ASP .NET Core Web API 项目。

设置项目名称和位置,并将框架设置为 .NET 8

安装 PuppeteerSharp 库

打开 Nuget 包管理器,搜索并安装 PuppeteerSharp 包。

创建 HtmlToPdfService

现在,我们将创建一个服务类来处理转换过程。在 Services 文件夹中添加新的 HtmlToService.cs 类文件。

using PuppeteerSharp;
using PuppeteerSharp.Media;

namespace HtmlToPdfWebApi.Services;

public class HtmlToPdfService
{
    private readonly IBrowser _browser;
    private readonly PdfOptions _pdfOptions;

    public HtmlToPdfService()
    {
        var browserFetcher = new BrowserFetcher();
        browserFetcher.DownloadAsync().GetAwaiter().GetResult();

        _browser = Puppeteer.LaunchAsync(new LaunchOptions
        {
            Headless = true
        }).GetAwaiter().GetResult();

        _pdfOptions = new PdfOptions
        {
            Format = PaperFormat.A4,
            MarginOptions = new MarginOptions
            {
                Top = "10mm",
                Right = "10mm",
                Bottom = "10mm",
                Left = "10mm",
            }
        };
    }

    public async Task ToFile(string htmlContent, string outputFilePath)
    {
        using var page = await _browser.NewPageAsync();

        await page.SetContentAsync(htmlContent);

        await page.PdfAsync(outputFilePath, _pdfOptions);

        await page.CloseAsync();
    }

    public async Task<byte[]> ToByteArray(string htmlContent)
    {
        using var page = await _browser.NewPageAsync();

        await page.SetContentAsync(htmlContent);

        var data = await page.PdfDataAsync(_pdfOptions);

        await page.CloseAsync();

        return data;
    }
}

构造 函数

在构造函数中,初始化和配置 IBrowserPdfOptions

BrowserFetcher 用于异步下载必要的浏览器二进制文件。

它以无外设模式(无 GUI)启动浏览器,以优化服务器环境的性能。

Pdf选项设置为定义 PDF 格式 (A4) 和边距(所有边长 10 毫米)。

ToFile() 方法

此方法将 HTML 内容转换为 PDF 文件,并将其保存到指定的文件路径。

它会在浏览器中创建一个新页面,并将页面内容设置为提供的 HTML。

它使用预定义的选项生成 PDF,并将其保存到指定的文件路径。

ToByteArray() 方法

此方法将 HTML 内容转换为 PDF,并将其作为字节数组返回。

ToFile() 方法类似,它会创建一个新页面并设置 HTML 内容。

它不是保存到文件中,而是将 PDF 数据检索为字节数组。

将 HTML 转换为 PDF

Controllers 文件夹中创建一个新的 InvoiceController.cs 类文件。

HtmlToPdfService 注入到构造函数中:

namespace HtmlToPdfWebApi.Controllers;

[Route("api/invoice")]
[ApiController]
public class InvoiceController : ControllerBase
{
    private readonly HtmlToPdfService htmlToPdfService;

    public InvoiceController(HtmlToPdfService htmlToPdfService)
    {
        this.htmlToPdfService = htmlToPdfService;
    }
}

现在,让我们定义将转换为 PDF 的 HTML 内容:

private string htmlContent = @"<!DOCTYPE html>
<html lang=""en"">
<head>
    <meta charset=""UTF-8"">
    <meta name=""viewport"" content=""width=device-width, initial-scale=1.0"">
    <title>Invoice</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f4f4f4;
        }
        .invoice-box {
            max-width: 800px;
            margin: 20px auto;
            padding: 30px;
            border: 1px solid #eee;
            background-color: #fff;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
        }
        .invoice-box table {
            width: 100%;
            line-height: inherit;
            text-align: left;
            border-collapse: collapse;
        }
        .invoice-box table td {
            padding: 8px;
            vertical-align: top;
        }
        .invoice-box table tr td:nth-child(2) {
            text-align: right;
        }
        .invoice-box table tr.top table td {
            padding-bottom: 20px;
        }
        .invoice-box table tr.top table td.title {
            font-size: 45px;
            line-height: 45px;
            color: #333;
        }
        .invoice-box table tr.information table td {
            padding-bottom: 40px;
        }
        .invoice-box table tr.heading td {
            background: #eee;
            border-bottom: 1px solid #ddd;
            font-weight: bold;
        }
        .invoice-box table tr.item td {
            border-bottom: 1px solid #eee;
        }
        .invoice-box table tr.item.last td {
            border-bottom: none;
        }
        .invoice-box table tr.total td:nth-child(2) {
            border-top: 2px solid #eee;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <div class=""invoice-box"">
        <table>
            <tr class=""top"">
                <td colspan=""2"">
                    <table>
                        <tr>
                            <td class=""title"">
                                <h2>Invoice</h2>
                            </td>
                            <td>
                                Invoice #: 123<br>
                                Created: January 1, 2024<br>
                                Due: January 15, 2024
                            </td>
                        </tr>
                    </table>
                </td>
            </tr>
            <tr class=""information"">
                <td colspan=""2"">
                    <table>
                        <tr>
                            <td>
                                Billing to:<br>
                                John Doe<br>
                                1234 Main St.<br>
                                Springfield, IL 62704
                            </td>
                            <td>
                                Company Name<br>
                                info@company.com
                            </td>
                        </tr>
                    </table>
                </td>
            </tr>
            <tr class=""heading"">
                <td>Item</td>
                <td>Price</td>
            </tr>
            <tr class=""item"">
                <td>Website design</td>
                <td>$300.00</td>
            </tr>
            <tr class=""item"">
                <td>Hosting (3 months)</td>
                <td>$75.00</td>
            </tr>
            <tr class=""item"">
                <td>Domain name (1 year)</td>
                <td>$10.00</td>
            </tr>
            <tr class=""item last"">
                <td>SEO Optimization</td>
                <td>$150.00</td>
            </tr>
            <tr class=""total"">
                <td></td>
                <td>Total: $535.00</td>
            </tr>
        </table>
    </div>
</body>
</html>
";

接下来,添加一个将返回 PDF 文件的新操作方法:

    [HttpGet("pdf")]
    public async Task<FileResult> GetPdf(CancellationToken cancellationToken)
    {
        var pdfContent = await htmlToPdfService.ToByteArray(htmlContent);
        return File(pdfContent, "application/pdf", "invoice.pdf");
    }

Program.cs

我们需要将 HtmlToPdfService 注册到服务容器。

打开Program.cs文件并将 HtmlToPdfService 注册为单一实例:

using HtmlToPdfWebApi.Services;  
  
var builder = WebApplication.CreateBuilder(args);  
  
// register HtmlToPdfService as singleton  
builder.Services.AddSingleton(new HtmlToPdfService());  
  
builder.Services.AddControllers();  
builder.Services.AddEndpointsApiExplorer();  
builder.Services.AddSwaggerGen();  
  
var app = builder.Build();  
app.UseSwagger();  
app.UseSwaggerUI();  
app.MapControllers();  
app.Run();

我们需要使用 new 关键字显式初始化类。这将确保 PuppeteerSharp 在应用程序启动期间下载必要的浏览器二进制文件。

运行应用程序

现在,让我们按 [F5] 键运行应用程序。大摇大摆的页面将打开。

执行终结点,然后单击“响应”部分中的“下载文件”链接:

PDF文件将被下载:

源代码获取:公众号回复消息【code:25486

相关代码下载地址
重要提示!:取消关注公众号后将无法再启用回复功能,不支持解封!
第一步:微信扫码关键公众号“架构师老卢”
第二步:在公众号聊天框发送code:25486,如:code:25486 获取下载地址
第三步:恭喜你,快去下载你想要的资源吧
阅读排行