如何在ASP.NET Core中從PDF文件中讀取資料
手動生成包裝單與標籤的問題
在每天處理500個訂單的倉庫中,挑選-包裝-出貨的迴圈無法容忍任何障礙。 從OMS螢幕上一個個列印包裝單、手動將訂單詳情複製到標籤模板中,或等待未與.NET後端良好整合的標籤軟體工具,每個訂單因此增加的秒數,漸漸累積成業務效率的真正損失。
錯誤風險隨著時間成本一起增加。當運送地址是手動記錄而非直接從訂單記錄中提取時,運送就可能出錯。 因為地址錯誤而退貨,所需的勞工和運費比大多數單個訂單的利潤還高。 承運商提供的標籤工具解決了地址問題,但不會產生倉庫需要的逐項包裝單來在封箱前驗證箱內內容物,這些仍然需要從不同的系統單獨列印。
大批量列印是大多數方案完全崩潰的地方。 釋放200個訂單的運營經理需要在輪班開始時就準備好包裝單,而不是通過每個訂單打開新的列印對話框的網路介面逐一生成。 格式需要適應每個倉庫的印表機,無論是雷射、噴墨還是熱感,僅此即可不需在倉庫工作站上安裝專有驅動程式。
場景一致:直銷消費者品牌每天包裝數百個訂單、B2B分銷商生成托盤運輸的多行包單、訂閱盒服務為裝配線工人列印項目清單、3PL供應商代表多個商戶客戶生成帶有不同標誌和退貨地址的品牌包單。
解決方案:利用IronPDF程式庫直接從訂單資料生成可列印的PDF檔案
IronPDF使.NET OMS能直接從訂單資料生成可列印的PDF包裝單和標籤。 當訂單進入"準備包裝"階段時,應用程式提取行項目、運送地址、承運人資訊和特殊指示,並填充為目標紙張大小的HTML模板,ChromePdfRenderer產生PDF。
倉庫員工在任何標準或熱感印表機上列印輸出,每個訂單一份文件或一整個挑選波次的多頁PDF在單一列印作業中處理完畢。 無需安裝專有標籤軟體、無需手動資料輸入步驟,也沒有按標籤計費的API費用。 渲染在現有的.NET應用程式中作為單一NuGet包運行,沒有外部過程。
實際運作方式
1. 訂單進入包裝佇列
訂單自動轉變為"準備包裝"狀態可在付款確認後自動進行,或由倉庫負責人從OMS釋放挑選波次時進行。 應用程式查詢批次中的每筆訂單資料庫,行項目包含SKU、產品名稱和數量; 運送地址; 承運人和服務級別; 如果可用,則提供預先分配的追蹤號; 以及任何特殊處理指示或禮物訊息。
波次中的每筆訂單都有其特定資料生成的PDF,來自相同的HTML模板。 對於200個訂單的波次,這就是200次渲染—每次僅耗毫秒—結果在列印作業之前被合併為單一檔案。
2. 模板相容兩種格式型別
包裝單模板(信紙或A4)包含行項目表單,打包員可核對每項產品,訂單號、收件地址和可掃描的訂單ID。 標籤模板以4×6英吋為目標(標準熱感標籤大小),包括收件以及退貨地址、承運人條碼區和運輸重量。
兩個模板都是應用團隊擁有的HTML和CSS文件。 更新包裝單以新增新列、更改3PL單據上的商戶標誌,或為新的熱感印表機型號調整標籤邊距,只需更改模板文件,無需重新編譯和重新部署業務邏輯。
範例HTML文件模板

3. 批量渲染後合併為一個列印作業
using IronPdf;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
string slipTemplate = await File.ReadAllTextAsync("Templates/packing-slip.html");
var slipPdfs = new List<PdfDocument>();
foreach (var order in pickWave)
{
string lineItemRows = string.Concat(order.Items.Select(i =>
$"<tr><td><input type='checkbox'></td><td>{i.Sku}</td><td>{i.ProductName}</td><td>{i.Quantity}</td></tr>"));
string html = slipTemplate
.Replace("{{OrderNumber}}", order.OrderNumber)
.Replace("{{ShipTo}}", order.ShippingAddress.Formatted)
.Replace("{{LineItems}}", lineItemRows)
.Replace("{{SpecialInstructions}}", order.SpecialInstructions ?? "None");
slipPdfs.Add(renderer.RenderHtmlAsPdf(html));
}
PdfDocument waveBatch = PdfDocument.Merge(slipPdfs);
waveBatch.SaveAs($"wave-{pickWave.WaveId}-slips.pdf");
using IronPdf;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
string slipTemplate = await File.ReadAllTextAsync("Templates/packing-slip.html");
var slipPdfs = new List<PdfDocument>();
foreach (var order in pickWave)
{
string lineItemRows = string.Concat(order.Items.Select(i =>
$"<tr><td><input type='checkbox'></td><td>{i.Sku}</td><td>{i.ProductName}</td><td>{i.Quantity}</td></tr>"));
string html = slipTemplate
.Replace("{{OrderNumber}}", order.OrderNumber)
.Replace("{{ShipTo}}", order.ShippingAddress.Formatted)
.Replace("{{LineItems}}", lineItemRows)
.Replace("{{SpecialInstructions}}", order.SpecialInstructions ?? "None");
slipPdfs.Add(renderer.RenderHtmlAsPdf(html));
}
PdfDocument waveBatch = PdfDocument.Merge(slipPdfs);
waveBatch.SaveAs($"wave-{pickWave.WaveId}-slips.pdf");
Imports IronPdf
Imports System.IO
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
Dim slipTemplate As String = Await File.ReadAllTextAsync("Templates/packing-slip.html")
Dim slipPdfs As New List(Of PdfDocument)()
For Each order In pickWave
Dim lineItemRows As String = String.Concat(order.Items.Select(Function(i) $"<tr><td><input type='checkbox'></td><td>{i.Sku}</td><td>{i.ProductName}</td><td>{i.Quantity}</td></tr>"))
Dim html As String = slipTemplate _
.Replace("{{OrderNumber}}", order.OrderNumber) _
.Replace("{{ShipTo}}", order.ShippingAddress.Formatted) _
.Replace("{{LineItems}}", lineItemRows) _
.Replace("{{SpecialInstructions}}", If(order.SpecialInstructions, "None"))
slipPdfs.Add(renderer.RenderHtmlAsPdf(html))
Next
Dim waveBatch As PdfDocument = PdfDocument.Merge(slipPdfs)
waveBatch.SaveAs($"wave-{pickWave.WaveId}-slips.pdf")
範例輸出PDF文件
PdfDocument.Merge()將每個單獨的單據合併為一個多頁PDF。 倉庫團隊為整個波次發出一個列印作業,一個工作站的點擊操作,一個輸出托盤即可收集。
4. 標籤尺寸通過渲染選項設置
using IronPdf;
var renderer = new ChromePdfRenderer();
// 4x6 inch thermal label — 288 x 432 points
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Custom;
renderer.RenderingOptions.CustomPaperWidth = 4;
renderer.RenderingOptions.CustomPaperHeight = 6;
renderer.RenderingOptions.MarginTop = 0;
renderer.RenderingOptions.MarginBottom = 0;
renderer.RenderingOptions.MarginLeft = 0;
renderer.RenderingOptions.MarginRight = 0;
string labelHtml = $@"
<div style='font-family:monospace; padding:4px;'>
<p><strong>SHIP TO:</strong><br/>{order.ShippingAddress.Formatted}</p>
<p><strong>FROM:</strong><br/>{order.ReturnAddress.Formatted}</p>
<p>Order: {order.OrderNumber} | Weight: {order.WeightLbs:F1} lbs</p>
<p>Carrier: {order.CarrierName} — {order.ServiceLevel}</p>
</div>";
PdfDocument label = renderer.RenderHtmlAsPdf(labelHtml);
label.SaveAs($"label-{order.OrderNumber}.pdf");
using IronPdf;
var renderer = new ChromePdfRenderer();
// 4x6 inch thermal label — 288 x 432 points
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Custom;
renderer.RenderingOptions.CustomPaperWidth = 4;
renderer.RenderingOptions.CustomPaperHeight = 6;
renderer.RenderingOptions.MarginTop = 0;
renderer.RenderingOptions.MarginBottom = 0;
renderer.RenderingOptions.MarginLeft = 0;
renderer.RenderingOptions.MarginRight = 0;
string labelHtml = $@"
<div style='font-family:monospace; padding:4px;'>
<p><strong>SHIP TO:</strong><br/>{order.ShippingAddress.Formatted}</p>
<p><strong>FROM:</strong><br/>{order.ReturnAddress.Formatted}</p>
<p>Order: {order.OrderNumber} | Weight: {order.WeightLbs:F1} lbs</p>
<p>Carrier: {order.CarrierName} — {order.ServiceLevel}</p>
</div>";
PdfDocument label = renderer.RenderHtmlAsPdf(labelHtml);
label.SaveAs($"label-{order.OrderNumber}.pdf");
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
' 4x6 inch thermal label — 288 x 432 points
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Custom
renderer.RenderingOptions.CustomPaperWidth = 4
renderer.RenderingOptions.CustomPaperHeight = 6
renderer.RenderingOptions.MarginTop = 0
renderer.RenderingOptions.MarginBottom = 0
renderer.RenderingOptions.MarginLeft = 0
renderer.RenderingOptions.MarginRight = 0
Dim labelHtml As String = $"
<div style='font-family:monospace; padding:4px;'>
<p><strong>SHIP TO:</strong><br/>{order.ShippingAddress.Formatted}</p>
<p><strong>FROM:</strong><br/>{order.ReturnAddress.Formatted}</p>
<p>Order: {order.OrderNumber} | Weight: {order.WeightLbs:F1} lbs</p>
<p>Carrier: {order.CarrierName} — {order.ServiceLevel}</p>
</div>"
Dim label As PdfDocument = renderer.RenderHtmlAsPdf(labelHtml)
label.SaveAs($"label-{order.OrderNumber}.pdf")
範例輸出PDF文件和運送標籤
零邊距讓CSS控制所有間距直至標籤邊緣,這對於熱感標籤格式至關重要,因為承運人條碼區必須接近紙張邊界幾毫米範圍內。
現實世界的好處
批量效率。 整個挑選波次合併為一個PDF意味著一個列印作業而非數百個。 倉庫員工不再需要等待單一訂單的列印對話框載入,輪班開始時間縮短。
列印相容性。 PDF在雷射、噴墨及熱感印表機上以一致性呈現,無需在倉庫工作站上安裝專有驅動或標籤軟體。 OMS生成的格式是每個倉庫印表機可接受的格式。
準確性。 行項目和地址直接從訂單記錄中提取。 無需手動抄錄步驟,也不存在地址或SKU錯誤輸入打包員之前的路徑。
靈活的格式。 相同生成管道通過切換HTML模板和頁面大小選項產生信紙大小的包裝單與4×6標籤。 無需單獨工具,無需單獨整合。
多租戶品牌化。 3PL供應商在模板路徑中填充merchantId變數,載入具商戶特色的HTML文件,每個客戶的單據均可通過相同管道攜帶自有標誌、退貨地址及品牌色彩,而無需額外邏輯。
無按標籤計費。 渲染在處理過程中運行。 無第三方標籤API被調用列印,無使用計量,沒有使高容量輪班比低容量輪班價格更高的定價模型。
結語
挑選-包裝-出貨迴圈是個產量問題。 訂單進入包裝佇列與貼有標籤的箱子離開碼頭之間的每個手動步驟都是一個限制,包裝單和標籤生成是最簡單在OMS中自動化的一個。
每種格式一個HTML模板,每筆訂單一個渲染調用,每個波次一個合併PDF,每個輪班一個列印作業。 IronPDF在C#中處理PDF生成的全部生命週期,從ironpdf.com上的渲染HTML模板到合併、儲存和串流。 如果您準備好測試管道搭配自身訂單資料與列印設置,開始您的免費30天試用,且在本週內獲得一個運行中的批次單據生成程式。




