C#でフォームをPDFに印刷する -- 完全な開発者向けガイド
並列PDFテンプレートの問題
Razorビューは既に構築されています。 請求書詳細ページはラインアイテムをレンダリングし、合計を計算し、会社のスタイルシートを適用します。 プロジェクトステータスページはタスクの内訳を表示し、マイルストーンが期限切れのときにのみ表示される条件付きセクションを含みます。 給与明細ビューは収入、控除、累計数字をHRチームが2週間かけて整えたテーブルにフォーマットします。 そのすべてが完了し、ステークホルダーが"PDFとしてダウンロード"ボタンを要求します。
標準の応答は第2のテンプレートを構築することです:PDFパスに同じレイアウトを再現するHTML文字列またはレポート定義です。 その第2のテンプレートは最初のコピーから始まり、すぐに分岐を開始します。 UIデザイナーはスプリント14で請求書ビューの表のスタイルを更新します。ダウンロードされた請求書が画面と異なるとユーザーが報告するまで、誰もPDFテンプレートを更新しません。 今、真実の2つのソースがあり、そのうちの1つは常にわずかに間違っています。
クライアントサイド for JavaScript PDFライブラリは重複を避けますが、サーバーでレンダリングされたデータ、認証されたデータ、サーバー側で計算された合計、ViewModelによって駆動される条件付きセクションはブラウザサイドのレンダラーへの引き渡しで生き残りません。 サーバーからのヘッドレスブラウザの自動化は脆弱で、インフラストラクチャの負担を増やし、コンテナ化された環境で予期せず失敗します。 ブラウザの印刷用のPDFは手動で印刷する1人のユーザーに役立ちます; それは生産アプリケーションの"PDFとしてダウンロード"ボタンではありません。
リアルなシナリオは実際のコストを表面化させます:フルフィルメントに対して注文詳細ページをダウンロードするeコマース管理者、プロジェクト管理ツールからプロジェクトステータスページをエクスポートするクライアント、給与明細をダウンロードする従業員、ルートサマリーを印刷するディスパッチャ。 全てはPDFが画面で見たものと全く同じに見えることを期待しています。
ソリューション:既存のビューをレンダリング、コピーではありません
IronPDFは、ASP.NET Coreアプリケーションが既存のRazorビュー—ブラウザを提供するものと同じもの—を直接PDFにレンダリングすることを可能にします。 PDFコントローラアクションは、標準ビューエンジンを使用してRazorビューをHTML文字列にレンダリングし、その文字列をChromePdfRenderer.RenderHtmlAsPdf()に渡し、結果をファイルダウンロードとして返します。
1つのビュー、2つの出力。 Razorビューが変更されると、PDF出力もそれに伴って自動的に変更され、調整は必要ありません。 並列テンプレートを保持する必要はなく、デバッグ用のクライアントサイドの回避策もなく、空間のあるヘッドレスブラウザプロセスも不要です。レンダリングは既存 for .NETアプリケーション内の単一のNuGetパッケージとして実行されます。
実際の使用方法
1. ビューはすでに存在しています:PDFアクションが新しいものです
/invoices/{id}にある請求書詳細ページは、ブラウザに提供しているか、またはPDFを生成しているかによらず、同じデータモデルをレンダリングします。 モデルには、ラインアイテム、合計、顧客の詳細、企業ブランディング、ビューに必要なすべてのデータが含まれています。 既存のInvoicesControllerには、そのモデルを埋めるDetailsアクションがあります。 PDFアクションはそれの兄弟であり、置き換えではありません。
ユーザーが"PDFをダウンロード"をクリックすると、リクエストが /invoices/{id}/pdf に入ります。 PDFアクションは同じサービスコールを使用して同じViewModelをフェッチし、モデルは同一です。 異なるのは次に何が起こるかです。
2. RazorビューがHTML文字列にレンダリングされます
ViewResultを返す代わりに、PDFアクションはビューレンダリングサービスを使用してRazorエンジンをビューのファイルとViewModelに適用し、出力を文字列としてキャプチャします。 これはASP.NET Core の共通パターンであり、ICompositeViewEngineを呼び出すためにIViewRenderServiceがコントローラに注入され、偽のActionContextでビューを実行し、レンダリングされたHTMLを返します。
レンダリングされたHTML文字列は完全です:すべてのデータが埋められ、すべての条件付きセクションが解決済みで、すべてのCSSクラス名が存在します。 それはサーバーサイドでキャプチャされたブラウザが受け取るのと同じHTMLです。
3. ChromePdfRendererはHTML文字列をPDF形式に変換します
using IronPdf;
[HttpGet("{id}/pdf")]
public async Task<IActionResult> DownloadInvoicePdf(int id)
{
var model = await _invoiceService.GetInvoiceViewModelAsync(id);
// Render the existing Razor view to an HTML string
string html = await _viewRenderer.RenderToStringAsync("Invoices/Details", model);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.MarginTop = 15;
renderer.RenderingOptions.MarginBottom = 15;
PdfDocument pdf = renderer.RenderHtmlAsPdf(html);
return File(pdf.BinaryData, "application/pdf"
$"Invoice-{model.InvoiceNumber}.pdf");
}
using IronPdf;
[HttpGet("{id}/pdf")]
public async Task<IActionResult> DownloadInvoicePdf(int id)
{
var model = await _invoiceService.GetInvoiceViewModelAsync(id);
// Render the existing Razor view to an HTML string
string html = await _viewRenderer.RenderToStringAsync("Invoices/Details", model);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.MarginTop = 15;
renderer.RenderingOptions.MarginBottom = 15;
PdfDocument pdf = renderer.RenderHtmlAsPdf(html);
return File(pdf.BinaryData, "application/pdf"
$"Invoice-{model.InvoiceNumber}.pdf");
}
Imports IronPdf
Imports Microsoft.AspNetCore.Mvc
<HttpGet("{id}/pdf")>
Public Async Function DownloadInvoicePdf(id As Integer) As Task(Of IActionResult)
Dim model = Await _invoiceService.GetInvoiceViewModelAsync(id)
' Render the existing Razor view to an HTML string
Dim html As String = Await _viewRenderer.RenderToStringAsync("Invoices/Details", model)
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
renderer.RenderingOptions.MarginTop = 15
renderer.RenderingOptions.MarginBottom = 15
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(html)
Return File(pdf.BinaryData, "application/pdf", $"Invoice-{model.InvoiceNumber}.pdf")
End Function
生成されたPDFドキュメント
CssMediaType.Printはビューのスタイルシート内の既存の@media printルールを適用します:ナビゲーションバーを非表示にし、アクションボタンを抑制し、印刷専用の間隔を適用し、Razorビュー自体に変更を要求せずに行います。
4. ビューに触れずにPDF出力を微調整する
ページ番号、カスタムマージン、文書タイトルを持つヘッダーなどのPDF固有の調整は、レンダラーで設定され、Razorビューではありません。 これにより、印刷ロジックがテンプレートから排除されます:
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='font-size:9px; color:#888; text-align:center; width:100%;'>
Invoice — Page {page} of {total-pages}
</div>",
DrawDividerLine = true
};
PdfDocument pdf = renderer.RenderHtmlAsPdf(html);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='font-size:9px; color:#888; text-align:center; width:100%;'>
Invoice — Page {page} of {total-pages}
</div>",
DrawDividerLine = true
};
PdfDocument pdf = renderer.RenderHtmlAsPdf(html);
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4
renderer.RenderingOptions.MarginTop = 20
renderer.RenderingOptions.MarginBottom = 20
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.HtmlFragment = "
<div style='font-size:9px; color:#888; text-align:center; width:100%;'>
Invoice — Page {page} of {total-pages}
</div>",
.DrawDividerLine = True
}
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(html)
出力PDFファイル
Razorビューは、それがブラウザにレンダリングされているかPDFにレンダリングされているかを知る必要はありません。 コントローラアクションがPDF固有の構成を所有し、ビューは純粋な表示テンプレートとして残ります。
実世界の利点
テンプレートの重複なし。 Razorビューは文書のレイアウトとコンテンツの唯一の信頼できる情報源です。 ブラウザとPDFは同じファイルからレンダリングされます。維持するための第2のテンプレートはなく、訂正するためのドリフトもありません。
即時導入。 ビューがすでに存在していれば、PDFエクスポートは1つのコントローラアクション先にあります。 レイアウトを再設計する必要はなく、テンプレートを再構築する必要はなく、異なるレンダリングシステムへの条件付きロジックを移植する必要もありません。
ピクセル正確な出力。 Chromiumベースのレンダリングは、CSSグリッド、フレックスボックス、Webフォント、メディアクエリがすべてPDFで機能することを意味します。 出力はブラウザが生成するものに一致し、低下した近似ではありません。
印刷専用のスタイリング。 ビューのスタイルシート内の@media printルールがPDFに表示されるものを制御し、ナビゲーションを非表示にし、用紙の列幅を調整し、コンテンツを再配置します。 別のテンプレートはありません。管理が別の印刷スタイルをインラインで設定する必要もありません。
保守性。 Razorビューを更新し、ブラウザ出力とPDF出力の両方が変更を反映します。 調整を調整するために、協調する第2のシステムはありませんし、デザイナーの変更がブラウザに到達するがPDFに到達しないというリスクもありません。
一文書あたりのコストはありません。 レンダリングは Web アプリケーション内でプロセス内で実行されます。 外部APIコールはなく、使用測定もなく、ダウンロード量に対してスケールするコストモデルもありません。
結び
Razorビューが既に構築されている場合、PDFエクスポートは新しい機能ではなく、既存作業の新しい配信パスです。 同じモデル、同じビュー、同じスタイリング:追加されるのは、ビューのHTML出力をキャプチャしてレンダラーを通じて渡し、ファイルとして返すコントローラーアクションだけです。
そのアーキテクチャは、コードベースをクリーンに保ち、ブラウザとの同期を永久に保ちます。 ironpdf.comでIronPDFはC#でのPDF生成のフルライフサイクルを処理し、HTMLコンテンツのレンダリングから保存、ストリーミング、ドキュメントの操作までを行います。 すでにRazorビューへのPDFエクスポートを導入する準備ができたら、無料の30日間トライアルを始め、出荷前に現在のブラウザのレンダリングと出力を照合しましょう。




