設置項目名稱和位置,并將框架設置為 .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;
}
}

構造 函數

在構造函數中,初始化和配置 IBrowser 和 PdfOptions。

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文件將被下載:

文章轉自微信公眾號@架構師老盧

上一篇:

VB.NET Excel插件集成kimi.ai API與DeepSeek-AI大模型

下一篇:

ASP.NET Core 2.0 建立規范的REST API GET和POST
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費