Konwertowanie HTML na PDF w C# z użyciem .NET 10
Dynamicznie generuj profesjonalne dokumenty PDF w ASP.NET Core, konwertując zawartość HTML na dopracowane pliki PDF i przesyłając je bezpośrednio do przeglądarki — bez konieczności przechowywania na dysku i zarządzania plikami tymczasowymi.
Podczas tworzenia nowoczesnych aplikacji internetowych w .NET Core często pojawia się potrzeba generowania dokumentów PDF na żądanie. Faktury muszą zostać pobrane w momencie zaksięgowania płatności. Raporty zgodności muszą pojawiać się natychmiast po kliknięciu przycisku "Eksportuj" przez audytora. Certyfikaty powinny być gotowe, zanim użytkownik zdąży się zastanowić, czy coś poszło nie tak. IronPDF obsługuje wszystkie te scenariusze dzięki bibliotece PDF opartej na Chromium, która konwertuje HTML — w tym CSS, JavaScript i czcionki internetowe — na plik PDF o pikselowej dokładności bez zapisywania czegokolwiek na dysku.
Ten przewodnik zawiera wszystko, co musisz wiedzieć: instalację biblioteki, generowanie faktur z ciągów HTML, strumieniowe przesyłanie raportów z danych Entity Framework, stosowanie nagłówków stron i ustawień zabezpieczeń oraz wdrażanie najlepszych praktyk, które zapewniają wysoką wydajność aplikacji ASP.NET o dużym natężeniu ruchu.
Co oznacza tworzenie plików PDF w locie?
"On the fly" oznacza, że dokument jest tworzony w pamięci w momencie wysłania żądania HTTP i wysyłany bezpośrednio do wywołującego. Żaden plik PDF nie jest zapisywany w systemie plików, żadne zadanie w tle nie umieszcza pracy w kolejce, a żadna pamięć podręczna nie przechowuje wyniku między żądaniami.
Takie podejście ma znaczenie z kilku powodów. Po pierwsze, środowiska wdrożeń w chmurze — Azure App Service, AWS Lambda, kontenery Docker — często działają w środowiskach, w których lokalny system plików jest tymczasowy lub tylko do odczytu. Generowanie pliku PDF do folderu tymczasowego, a następnie odczytywanie go z powrotem jest w tych środowiskach zawodne. Po drugie, unikanie zapisów na dysku zmniejsza powierzchnię ataku: nie ma pliku resztkowego, który kolejne żądanie mogłoby przypadkowo dostarczyć niewłaściwemu użytkownikowi. Po trzecie, generowanie wyłącznie w pamięci jest zazwyczaj szybsze, ponieważ eliminuje dwie operacje wejścia/wyjścia (zapis i odczyt) w ścieżce krytycznej.
ChromePdfRenderer IronPDF udostępnia właściwość .BinaryData i właściwość .Stream w każdym wygenerowanym dokumencie. Obie mogą być przekazywane bezpośrednio do ASP.NET Core FileResult, co sprawia, że strumieniowanie w praktyce to jedna linijka.
Jak zainstalować IronPDF w projekcie ASP.NET Core?
Dodaj pakiet NuGet za pomocą konsoli menedżera pakietów lub interfejsu CLI platformy .NET:
:ProductInstall
dotnet add package IronPdf
:ProductInstall
dotnet add package IronPdf
Po zainstalowaniu pakietu, ustaw swój klucz licencyjny podczas uruchamiania aplikacji – zazwyczaj w Program.cs przed utworzeniem pierwszego renderera:
using IronPdf;
// Place license activation before any IronPDF call
License.LicenseKey = "YOUR-LICENSE-KEY";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
// Register ChromePdfRenderer as a singleton so the Chromium engine
// is initialised once and reused across all requests.
builder.Services.AddSingleton<ChromePdfRenderer>();
var app = builder.Build();
app.MapDefaultControllerRoute();
app.Run();
using IronPdf;
// Place license activation before any IronPDF call
License.LicenseKey = "YOUR-LICENSE-KEY";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
// Register ChromePdfRenderer as a singleton so the Chromium engine
// is initialised once and reused across all requests.
builder.Services.AddSingleton<ChromePdfRenderer>();
var app = builder.Build();
app.MapDefaultControllerRoute();
app.Run();
Imports IronPdf
' Place license activation before any IronPDF call
License.LicenseKey = "YOUR-LICENSE-KEY"
Dim builder = WebApplication.CreateBuilder(args)
builder.Services.AddControllersWithViews()
' Register ChromePdfRenderer as a singleton so the Chromium engine
' is initialised once and reused across all requests.
builder.Services.AddSingleton(Of ChromePdfRenderer)()
Dim app = builder.Build()
app.MapDefaultControllerRoute()
app.Run()
Rejestracja ChromePdfRenderer jako singleton jest ważna. Renderer uruchamia wewnętrzny podproces Chromium przy pierwszym użyciu. Jeśli tworzysz nową instancję dla każdego żądania, ponosisz ten koszt uruchomienia przy każdym wywołaniu, co powoduje opóźnienie rzędu setek milisekund przy dużym obciążeniu. Instancja singletonowa jest bezpieczna dla wątków i obsługuje równoczesne żądania renderowania bez dodatkowej konfiguracji.
Aby uzyskać szerszy przegląd opcji instalacji, w tym konfiguracji pliku NuGet.config dla prywatnych kanałów, odwiedź stronę z przeglądem instalacji.
Jak wygenerować plik PDF z fakturą na podstawie ciągu znaków HTML?
Najczęstszym przykładem zastosowania w czasie rzeczywistym jest generowanie dokumentów transakcyjnych — faktur, paragonów, potwierdzeń zamówień — gdzie treść zmienia się w zależności od żądania, ale układ pozostaje stały.
Schemat jest następujący: skonstruuj ciąg HTML z interpolowanymi danymi, przekaż go do RenderHtmlAsPdf i zwróć wynik binarny jako pobieranie pliku.
using IronPdf;
using Microsoft.AspNetCore.Mvc;
public class DocumentController : Controller
{
private readonly ChromePdfRenderer _renderer;
public DocumentController(ChromePdfRenderer renderer)
{
_renderer = renderer;
}
[HttpGet("invoice/{orderId:int}")]
public IActionResult GetInvoice(int orderId)
{
// In a real application, fetch this from your database or order service.
var order = GetOrderData(orderId);
string html = $"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body {{font-family: Arial, sans-serif; margin: 40px; color: #333;}}
h1 {{color: #1a56db;}}
table {{width: 100%; border-collapse: collapse; margin-top: 24px;}}
th, td {{padding: 10px 14px; border: 1px solid #d1d5db; text-align: left;}}
th {{background: #f3f4f6;}}
tfoot td {{font-weight: bold;}}
</style>
</head>
<body>
<h1>Invoice #{order.InvoiceNumber}</h1>
<p>Date: {DateTime.UtcNow:yyyy-MM-dd} | Customer: {order.CustomerName}</p>
<table>
<thead><tr><th>Item</th><th>Qty</th><th>Unit Price</th><th>Subtotal</th></tr></thead>
<tbody>
{string.Join("", order.Items.Select(i =>
$"<tr><td>{i.Name}</td><td>{i.Quantity}</td>" +
$"<td>${i.UnitPrice:F2}</td><td>${i.Quantity * i.UnitPrice:F2}</td></tr>"))}
</tbody>
<tfoot>
<tr><td colspan="3">Total</td><td>${order.Items.Sum(i => i.Quantity * i.UnitPrice):F2}</td></tr>
</tfoot>
</table>
</body>
</html>
""";
var pdf = _renderer.RenderHtmlAsPdf(html);
return File(pdf.BinaryData, "application/pdf", $"invoice-{orderId}.pdf");
}
}
using IronPdf;
using Microsoft.AspNetCore.Mvc;
public class DocumentController : Controller
{
private readonly ChromePdfRenderer _renderer;
public DocumentController(ChromePdfRenderer renderer)
{
_renderer = renderer;
}
[HttpGet("invoice/{orderId:int}")]
public IActionResult GetInvoice(int orderId)
{
// In a real application, fetch this from your database or order service.
var order = GetOrderData(orderId);
string html = $"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body {{font-family: Arial, sans-serif; margin: 40px; color: #333;}}
h1 {{color: #1a56db;}}
table {{width: 100%; border-collapse: collapse; margin-top: 24px;}}
th, td {{padding: 10px 14px; border: 1px solid #d1d5db; text-align: left;}}
th {{background: #f3f4f6;}}
tfoot td {{font-weight: bold;}}
</style>
</head>
<body>
<h1>Invoice #{order.InvoiceNumber}</h1>
<p>Date: {DateTime.UtcNow:yyyy-MM-dd} | Customer: {order.CustomerName}</p>
<table>
<thead><tr><th>Item</th><th>Qty</th><th>Unit Price</th><th>Subtotal</th></tr></thead>
<tbody>
{string.Join("", order.Items.Select(i =>
$"<tr><td>{i.Name}</td><td>{i.Quantity}</td>" +
$"<td>${i.UnitPrice:F2}</td><td>${i.Quantity * i.UnitPrice:F2}</td></tr>"))}
</tbody>
<tfoot>
<tr><td colspan="3">Total</td><td>${order.Items.Sum(i => i.Quantity * i.UnitPrice):F2}</td></tr>
</tfoot>
</table>
</body>
</html>
""";
var pdf = _renderer.RenderHtmlAsPdf(html);
return File(pdf.BinaryData, "application/pdf", $"invoice-{orderId}.pdf");
}
}
Imports IronPdf
Imports Microsoft.AspNetCore.Mvc
Public Class DocumentController
Inherits Controller
Private ReadOnly _renderer As ChromePdfRenderer
Public Sub New(renderer As ChromePdfRenderer)
_renderer = renderer
End Sub
<HttpGet("invoice/{orderId:int}")>
Public Function GetInvoice(orderId As Integer) As IActionResult
' In a real application, fetch this from your database or order service.
Dim order = GetOrderData(orderId)
Dim html As String = $"
<!DOCTYPE html>
<html lang=""en"">
<head>
<meta charset=""utf-8"">
<style>
body {{font-family: Arial, sans-serif; margin: 40px; color: #333;}}
h1 {{color: #1a56db;}}
table {{width: 100%; border-collapse: collapse; margin-top: 24px;}}
th, td {{padding: 10px 14px; border: 1px solid #d1d5db; text-align: left;}}
th {{background: #f3f4f6;}}
tfoot td {{font-weight: bold;}}
</style>
</head>
<body>
<h1>Invoice #{order.InvoiceNumber}</h1>
<p>Date: {DateTime.UtcNow:yyyy-MM-dd} | Customer: {order.CustomerName}</p>
<table>
<thead><tr><th>Item</th><th>Qty</th><th>Unit Price</th><th>Subtotal</th></tr></thead>
<tbody>
{String.Join("", order.Items.Select(Function(i)
$"<tr><td>{i.Name}</td><td>{i.Quantity}</td>" +
$"<td>${i.UnitPrice:F2}</td><td>${i.Quantity * i.UnitPrice:F2}</td></tr>"))}
</tbody>
<tfoot>
<tr><td colspan=""3"">Total</td><td>${order.Items.Sum(Function(i) i.Quantity * i.UnitPrice):F2}</td></tr>
</tfoot>
</table>
</body>
</html>
"
Dim pdf = _renderer.RenderHtmlAsPdf(html)
Return File(pdf.BinaryData, "application/pdf", $"invoice-{orderId}.pdf")
End Function
End Class
RenderHtmlAsPdf przetwarza pełny dokument HTML – używaś tego samego silnika Chromium, który zasila Google Chrome, obsługując CSS grid, Flexbox, czcionki webowe, a nawet SVG osadzone. Zwrócony PdfDocument udostępnia BinaryData (a byte[]) i Stream (a MemoryStream). Przekazanie BinaryData do File() z "application/pdf" i nazwą pliku uruchamia pobieranie w przeglądarce.
W przypadku układów wymagających idealnej wierności pikselowej należy zapoznać się z przewodnikiem renderowania HTML do PDF, który obejmuje responsywny CSS, niestandardowe czcionki i renderowanie JavaScript.
Jak wygląda wygenerowany plik PDF z fakturą?

Jak przesyłać plik PDF bezpośrednio do przeglądarki bez okna dialogowego pobierania?
Serwowanie PDF w przeglądarce – otwieranie go w wbudowanej przeglądarce, zamiast pobierania – wymaga dwóch małych zmian: ustaw Content-Disposition na inline i pomiń nazwę pliku z wywołania File().
[HttpPost("report/preview")]
public async Task<IActionResult> PreviewReport([FromBody] ReportRequest request)
{
string html = BuildReportHtml(request);
var pdfDocument = await _renderer.RenderHtmlAsPdfAsync(html);
// "inline" tells the browser to display rather than download.
Response.Headers["Content-Disposition"] = "inline; filename=report.pdf";
return new FileContentResult(pdfDocument.BinaryData, "application/pdf");
}
[HttpPost("report/preview")]
public async Task<IActionResult> PreviewReport([FromBody] ReportRequest request)
{
string html = BuildReportHtml(request);
var pdfDocument = await _renderer.RenderHtmlAsPdfAsync(html);
// "inline" tells the browser to display rather than download.
Response.Headers["Content-Disposition"] = "inline; filename=report.pdf";
return new FileContentResult(pdfDocument.BinaryData, "application/pdf");
}
Imports Microsoft.AspNetCore.Mvc
<HttpPost("report/preview")>
Public Async Function PreviewReport(<FromBody> request As ReportRequest) As Task(Of IActionResult)
Dim html As String = BuildReportHtml(request)
Dim pdfDocument = Await _renderer.RenderHtmlAsPdfAsync(html)
' "inline" tells the browser to display rather than download.
Response.Headers("Content-Disposition") = "inline; filename=report.pdf"
Return New FileContentResult(pdfDocument.BinaryData, "application/pdf")
End Function
Zalecane jest użycie asynchronicznego przeciążenia RenderHtmlAsPdfAsync dla kontrolerów ASP.NET Core ponieważ zwalnia to wątek puli podczas renderowania Chromium, co utrzymuje serwer responsywnym przy równoczesnym obciążeniu.
Jak działa generowanie plików PDF na podstawie pamięci?

Tablica bajtowa pdfDocument.BinaryData całkowicie znajduje się w zarządzanej pamięci. Nie ma tu żadnych pośrednich ścieżek do plików. Nagłówek Content-Disposition kontroluje, czy PDF jest wyświetlany w przeglądarce, czy oferowany jako pobieranie – jest to zachowanie przeglądarki zdefiniowane przez specyfikację HTTP. Aby uzyskać więcej informacji na temat podejścia MemoryStream, w tym przesyłania strumieniowego do usługi Azure Blob Storage, zapoznaj się z dokumentacją dotyczącą strumienia pamięci w formacie PDF.
Jak generować pliki PDF na podstawie wyników zapytań Entity Framework Core?
Większość aplikacji biznesowych pobiera dane raportów z bazy danych, zamiast tworzyć je w momencie wywołania. Poniższy wzorzec wysyła zapytanie do Entity Framework Core, tworzy tabelę HTML i zwraca plik PDF — wszystko w ramach jednej akcji kontrolera.
[HttpGet("report/monthly")]
public async Task<IActionResult> MonthlyReport(int year, int month)
{
// Pull aggregated transaction data from EF Core.
var rows = await _dbContext.Transactions
.Where(t => t.Date.Year == year && t.Date.Month == month)
.GroupBy(t => t.Category)
.Select(g => new { Category = g.Key, Count = g.Count(), Total = g.Sum(t => t.Amount) })
.OrderByDescending(g => g.Total)
.ToListAsync();
string tableRows = string.Join("", rows.Select(r =>
$"<tr><td>{r.Category}</td><td>{r.Count}</td><td>${r.Total:F2}</td></tr>"));
string html = $"""
<html><body style="font-family:Arial,sans-serif;padding:32px">
<h1>Monthly Report -- {month:D2}/{year}</h1>
<table style="width:100%;border-collapse:collapse">
<thead>
<tr style="background:#e5e7eb">
<th style="padding:8px;border:1px solid #d1d5db">Category</th>
<th style="padding:8px;border:1px solid #d1d5db">Transactions</th>
<th style="padding:8px;border:1px solid #d1d5db">Total</th>
</tr>
</thead>
<tbody>{tableRows}</tbody>
</table>
</body></html>
""";
var pdf = _renderer.RenderHtmlAsPdf(html);
pdf.MetaData.Title = $"Monthly Report {month:D2}/{year}";
pdf.MetaData.Author = "Reporting System";
return File(pdf.BinaryData, "application/pdf", $"report-{year}-{month:D2}.pdf");
}
[HttpGet("report/monthly")]
public async Task<IActionResult> MonthlyReport(int year, int month)
{
// Pull aggregated transaction data from EF Core.
var rows = await _dbContext.Transactions
.Where(t => t.Date.Year == year && t.Date.Month == month)
.GroupBy(t => t.Category)
.Select(g => new { Category = g.Key, Count = g.Count(), Total = g.Sum(t => t.Amount) })
.OrderByDescending(g => g.Total)
.ToListAsync();
string tableRows = string.Join("", rows.Select(r =>
$"<tr><td>{r.Category}</td><td>{r.Count}</td><td>${r.Total:F2}</td></tr>"));
string html = $"""
<html><body style="font-family:Arial,sans-serif;padding:32px">
<h1>Monthly Report -- {month:D2}/{year}</h1>
<table style="width:100%;border-collapse:collapse">
<thead>
<tr style="background:#e5e7eb">
<th style="padding:8px;border:1px solid #d1d5db">Category</th>
<th style="padding:8px;border:1px solid #d1d5db">Transactions</th>
<th style="padding:8px;border:1px solid #d1d5db">Total</th>
</tr>
</thead>
<tbody>{tableRows}</tbody>
</table>
</body></html>
""";
var pdf = _renderer.RenderHtmlAsPdf(html);
pdf.MetaData.Title = $"Monthly Report {month:D2}/{year}";
pdf.MetaData.Author = "Reporting System";
return File(pdf.BinaryData, "application/pdf", $"report-{year}-{month:D2}.pdf");
}
Imports Microsoft.AspNetCore.Mvc
Imports System.Threading.Tasks
Imports System.Linq
<HttpGet("report/monthly")>
Public Async Function MonthlyReport(year As Integer, month As Integer) As Task(Of IActionResult)
' Pull aggregated transaction data from EF Core.
Dim rows = Await _dbContext.Transactions _
.Where(Function(t) t.Date.Year = year AndAlso t.Date.Month = month) _
.GroupBy(Function(t) t.Category) _
.Select(Function(g) New With {Key .Category = g.Key, Key .Count = g.Count(), Key .Total = g.Sum(Function(t) t.Amount)}) _
.OrderByDescending(Function(g) g.Total) _
.ToListAsync()
Dim tableRows As String = String.Join("", rows.Select(Function(r) $"<tr><td>{r.Category}</td><td>{r.Count}</td><td>${r.Total:F2}</td></tr>"))
Dim html As String = $"
<html><body style='font-family:Arial,sans-serif;padding:32px'>
<h1>Monthly Report -- {month:D2}/{year}</h1>
<table style='width:100%;border-collapse:collapse'>
<thead>
<tr style='background:#e5e7eb'>
<th style='padding:8px;border:1px solid #d1d5db'>Category</th>
<th style='padding:8px;border:1px solid #d1d5db'>Transactions</th>
<th style='padding:8px;border:1px solid #d1d5db'>Total</th>
</tr>
</thead>
<tbody>{tableRows}</tbody>
</table>
</body></html>
"
Dim pdf = _renderer.RenderHtmlAsPdf(html)
pdf.MetaData.Title = $"Monthly Report {month:D2}/{year}"
pdf.MetaData.Author = "Reporting System"
Return File(pdf.BinaryData, "application/pdf", $"report-{year}-{month:D2}.pdf")
End Function
Ustawienie pdf.MetaData.Title i pdf.MetaData.Author osadza te informacje we właściwościach dokumentu PDF, co jest przydatne do śledzenia zgodności oraz systemów zarządzania dokumentami. W przypadku bardziej złożonych układów raportów warto rozważyć zastosowanie stylów drukowania CSS, wyraźnych podziałów stron oraz osadzonych obrazów wykresów.
Jak zastosować nagłówki, stopki i zabezpieczenia w wygenerowanych plikach PDF?
Dokumenty produkcyjne często wymagają nagłówków z tytułem dokumentu, stopek z numerami stron oraz zabezpieczeń dostępu, które zapobiegają nieautoryzowanemu drukowaniu lub kopiowaniu. ChromePdfRenderOptions IronPDF obejmuje wszystkie te wymagania.
[HttpPost("document/secured")]
public async Task<IActionResult> GenerateSecuredDocument([FromBody] SecuredDocRequest request)
{
var renderOptions = new ChromePdfRenderOptions
{
RozmiarPapieru = RozmiarPapieruPDF.A4,
MarginTop = 45,
MarginBottom = 45,
MarginLeft = 25,
MarginRight = 25,
Włącz JavaScript = true,
WaitFor = new WaitFor { RenderDelay = 500 }
};
renderOptions.TextHeader = new NaglowekStopkaTekst
{
CenterText = request.DocumentTitle,
DrawDividerLine = true,
FontSize = 11
};
renderOptions.TextFooter = new NaglowekStopkaTekst
{
LeftText = "{date} {time}",
RightText = "Page {page} of {total-pages}",
FontSize = 9
};
_renderer.RenderingOptions = renderOptions;
var pdf = await _renderer.RenderHtmlAsPdfAsync(request.HtmlContent);
if (request.RequirePassword)
{
pdf.SecuritySettings.OwnerPassword = request.OwnerPassword;
pdf.SecuritySettings.UserPassword = request.UserPassword;
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.NoPrint;
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
}
return File(pdf.BinaryData, "application/pdf", $"{request.FileName}.pdf");
}
[HttpPost("document/secured")]
public async Task<IActionResult> GenerateSecuredDocument([FromBody] SecuredDocRequest request)
{
var renderOptions = new ChromePdfRenderOptions
{
RozmiarPapieru = RozmiarPapieruPDF.A4,
MarginTop = 45,
MarginBottom = 45,
MarginLeft = 25,
MarginRight = 25,
Włącz JavaScript = true,
WaitFor = new WaitFor { RenderDelay = 500 }
};
renderOptions.TextHeader = new NaglowekStopkaTekst
{
CenterText = request.DocumentTitle,
DrawDividerLine = true,
FontSize = 11
};
renderOptions.TextFooter = new NaglowekStopkaTekst
{
LeftText = "{date} {time}",
RightText = "Page {page} of {total-pages}",
FontSize = 9
};
_renderer.RenderingOptions = renderOptions;
var pdf = await _renderer.RenderHtmlAsPdfAsync(request.HtmlContent);
if (request.RequirePassword)
{
pdf.SecuritySettings.OwnerPassword = request.OwnerPassword;
pdf.SecuritySettings.UserPassword = request.UserPassword;
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.NoPrint;
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
}
return File(pdf.BinaryData, "application/pdf", $"{request.FileName}.pdf");
}
Imports Microsoft.AspNetCore.Mvc
<HttpPost("document/secured")>
Public Async Function GenerateSecuredDocument(<FromBody> request As SecuredDocRequest) As Task(Of IActionResult)
Dim renderOptions As New ChromePdfRenderOptions With {
.RozmiarPapieru = RozmiarPapieruPDF.A4,
.MarginTop = 45,
.MarginBottom = 45,
.MarginLeft = 25,
.MarginRight = 25,
.WłączJavaScript = True,
.WaitFor = New WaitFor With {.RenderDelay = 500}
}
renderOptions.TextHeader = New NaglowekStopkaTekst With {
.CenterText = request.DocumentTitle,
.DrawDividerLine = True,
.FontSize = 11
}
renderOptions.TextFooter = New NaglowekStopkaTekst With {
.LeftText = "{date} {time}",
.RightText = "Page {page} of {total-pages}",
.FontSize = 9
}
_renderer.RenderingOptions = renderOptions
Dim pdf = Await _renderer.RenderHtmlAsPdfAsync(request.HtmlContent)
If request.RequirePassword Then
pdf.SecuritySettings.OwnerPassword = request.OwnerPassword
pdf.SecuritySettings.UserPassword = request.UserPassword
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.NoPrint
pdf.SecuritySettings.AllowUserCopyPasteContent = False
End If
Return File(pdf.BinaryData, "application/pdf", $"{request.FileName}.pdf")
End Function
Ustawienie WaitFor.RenderDelay jest szczególnie przydatne, gdy twój HTML zawiera biblioteki wykresów, takie jak Chart.js czy ApexCharts, które kończą rysowanie asynchronicznie. Ustawienie opóźnienia na 300–500 ms gwarantuje, że Chromium uchwyci ostateczny stan renderowania. W przypadku dokumentów, które muszą spełniać standardy archiwizacji, należy połączyć powyższe podejście z zgodnością z formatem PDF/A i podpisami cyfrowymi.
Tokeny {page} i {total-pages} w tekście stopki są automatycznie rozwiązywane przez IronPDF podczas renderowania. Dodatkowe opcje nagłówków i stopek obejmują nagłówki oparte na HTML do umieszczania logo oraz możliwości nadpisywania dla poszczególnych sekcji.
Jakie opcje renderowania są dostępne?
Poniższa tabela podsumowuje najbardziej użyteczne właściwości ChromePdfRenderOptions do generowania na bieżąco:
| Właściwość | Typ | Cel |
|---|---|---|
| RozmiarPapieru | RozmiarPapieruPDF | Ustawia wymiary strony (A4, Letter, Legal, niestandardowe) |
| MarginTop / MarginBottom | int (mm) | Kontroluje odstępy w obszarze drukowania |
| Włącz JavaScript | bool | Zezwala na wykonanie kodu JS przed przechwyceniem |
| WaitFor.RenderDelay | int (ms) | Przechwytywanie opóźnień dla renderowania asynchronicznego |
| TextHeader / TextFooter | NaglowekStopkaTekst | Nagłówki i stopki stron |
| HtmlHeader / HtmlFooter | NaglowekStopkaHtml | Nagłówki/stopki w formacie HTML z obrazami |
| GrayScale | bool | Wynik: monochromatyczny plik PDF |
| FitToPaperWidth | bool | Dostosowuje szeroką treść do strony |
Jakie są najlepsze praktyki dotyczące wydajności przy generowaniu dużych ilości plików PDF?
Gdy pojedynczy serwer obsługuje setki równoczesnych żądań dotyczących plików PDF, kilka decyzji architektonicznych ma ogromny wpływ na przepustowość i opóźnienia.
Rejestracja renderera jako singleton. Jak pokazano w sekcji instalacji, rejestracja ChromePdfRenderer jako singleton w kontenerze DI unika kosztów uruchamiania nowego procesu podrzędnego Chromium dla każdego żądania. Zgodnie z zaleceniami dotyczącymi wydajności ASP.NET Core Microsoftu, minimalizacja alokacji obiektów i ponowne wykorzystanie kosztownych zasobów to najbardziej wpływowe optymalizacje dostępne.
Zawsze używaj asynchroniczności. RenderHtmlAsPdfAsync zwraca Task<PdfDocument> i zawiesza wątek kontrolera, gdy Chromium pracuje. Uwalnia to pulę wątków do równoległej obsługi innych przychodzących żądań, dlatego dokumentacja async zaleca to przeciążenie dla hostów internetowych. Przeładowanie synchroniczne jest odpowiednie tylko dla narzędzi konsolowych lub usług działających w tle, gdzie blokowanie wątków jest dopuszczalne.
Transmisja bezpośrednia, pomijaj pośrednią tablicę, jeśli to możliwe. Dla dużych PDF-ów, .Stream może być zapisana bezpośrednio do treści odpowiedzi bez materializacji pełnej tablicy bajtów:
[HttpGet("document/large")]
public IActionResult StreamLargeDocument(int documentId)
{
string html = BuildLargeDocumentHtml(documentId);
var pdf = _renderer.RenderHtmlAsPdf(html);
// Stream.Position is already at 0; no seek needed.
return File(pdf.Stream, "application/pdf", $"document-{documentId}.pdf");
}
[HttpGet("document/large")]
public IActionResult StreamLargeDocument(int documentId)
{
string html = BuildLargeDocumentHtml(documentId);
var pdf = _renderer.RenderHtmlAsPdf(html);
// Stream.Position is already at 0; no seek needed.
return File(pdf.Stream, "application/pdf", $"document-{documentId}.pdf");
}
Imports Microsoft.AspNetCore.Mvc
<HttpGet("document/large")>
Public Function StreamLargeDocument(documentId As Integer) As IActionResult
Dim html As String = BuildLargeDocumentHtml(documentId)
Dim pdf = _renderer.RenderHtmlAsPdf(html)
' Stream.Position is already at 0; no seek needed.
Return File(pdf.Stream, "application/pdf", $"document-{documentId}.pdf")
End Function
Usuń po użyciu. PdfDocument implementuje IDisposable. Opakowanie go w instrukcję using uwalnia podstawowy bufor pamięci szybko, co ma znaczenie przy generowaniu wielu dużych PDF-ów jedno po drugim:
using var pdf = _renderer.RenderHtmlAsPdf(html);
byte[] data = pdf.BinaryData;
// pdf is disposed here; data is safely copied to the local array.
return File(data, "application/pdf", "output.pdf");
using var pdf = _renderer.RenderHtmlAsPdf(html);
byte[] data = pdf.BinaryData;
// pdf is disposed here; data is safely copied to the local array.
return File(data, "application/pdf", "output.pdf");
Imports System.IO
Using pdf = _renderer.RenderHtmlAsPdf(html)
Dim data As Byte() = pdf.BinaryData
' pdf is disposed here; data is safely copied to the local array.
Return File(data, "application/pdf", "output.pdf")
End Using
W przypadku wskazówek dotyczących wdrażania w chmurze obejmujących środowiska Azure, AWS, Docker i Linux dokumentacja IronPDF zawiera uwagi dotyczące konfiguracji specyficzne dla danego środowiska. Jeśli pierwsze renderowanie po uruchomieniu jest wolne, skonsultuj przewodnik rozgrzewania i buforowania w celu strategii przed-inicjalizacji renderera przed przybyciem pierwszego żądania użytkownika.
Jak dodać znak wodny do wygenerowanego pliku PDF?
Przed wysłaniem strumieniowym do każdej strony wygenerowanego dokumentu można dodać tekstowy lub graficzny znak wodny:
[HttpGet("document/draft/{id:int}")]
public IActionResult GetDraftDocument(int id)
{
string html = BuildDocumentHtml(id);
var pdf = _renderer.RenderHtmlAsPdf(html);
// Stamp "DRAFT" diagonally across every page.
pdf.ApplyWatermark(
"<h1 style='color:rgba(200,0,0,0.25);transform:rotate(-45deg)'>DRAFT</h1>",
rotation: 45,
opacity: 30
);
return File(pdf.BinaryData, "application/pdf", $"draft-{id}.pdf");
}
[HttpGet("document/draft/{id:int}")]
public IActionResult GetDraftDocument(int id)
{
string html = BuildDocumentHtml(id);
var pdf = _renderer.RenderHtmlAsPdf(html);
// Stamp "DRAFT" diagonally across every page.
pdf.ApplyWatermark(
"<h1 style='color:rgba(200,0,0,0.25);transform:rotate(-45deg)'>DRAFT</h1>",
rotation: 45,
opacity: 30
);
return File(pdf.BinaryData, "application/pdf", $"draft-{id}.pdf");
}
<AttributeUsage(AttributeTargets.Method, Inherited:=True, AllowMultiple:=False)>
Public Class HttpGetAttribute
Inherits Attribute
Public Sub New(route As String)
End Sub
End Class
<HttpGet("document/draft/{id:int}")>
Public Function GetDraftDocument(id As Integer) As IActionResult
Dim html As String = BuildDocumentHtml(id)
Dim pdf = _renderer.RenderHtmlAsPdf(html)
' Stamp "DRAFT" diagonally across every page.
pdf.ApplyWatermark(
"<h1 style='color:rgba(200,0,0,0.25);transform:rotate(-45deg)'>DRAFT</h1>",
rotation:=45,
opacity:=30
)
Return File(pdf.BinaryData, "application/pdf", $"draft-{id}.pdf")
End Function
Pełne opcje konfiguracji znaków wodnych, w tym znaki wodne w postaci obrazów i kontrolę na poziomie poszczególnych stron, można znaleźć w dokumentacji dotyczącej znaków wodnych.
Jakie są Twoje kolejne kroki?
Dynamiczne generowanie PDF w ASP.NET Core podąża za spójnym schematem: zbuduj swój HTML, wywołaj RenderHtmlAsPdf lub jego asynchroniczne przeciążenie, i zwróć wynik przez FileResult. IronPDF zajmuje się wszystkim pomiędzy — renderowaniem Chromium, stosowaniem CSS, wykonywaniem JavaScript — bez konieczności operacji wejścia/wyjścia na dysk na żadnym etapie.
W tym miejscu można rozważyć kilka kierunków działania w zależności od wymagań aplikacji. Jeśli Twoje pliki PDF wymagają połączenia wielu dokumentów źródłowych, przewodnik dotyczący scałania i dzielenia opisuje łączenie istniejących plików PDF ze świeżo wyrenderowanymi stronami. Jeśli chcesz, aby użytkownicy wypełniali i przesyłali formularze osadzone w pliku PDF, dokumentacja dotycząca formularzy interaktywnych pokazuje, jak tworzyć i odczytywać wartości pól. W przypadku branż podlegających regulacjom zgodność z formatem PDF/A oraz standardem dostępności PDF/UA gwarantuje, że dokumenty spełniają normy archiwizacji i dostępności.
Jeśli rozważasz wybór IronPDF spośród alternatywnych rozwiązań, porównanie iText vs IronPDF zawiera szczegółowe zestawienie techniczne obu produktów. Gdy będziesz gotowy do przejścia do środowiska produkcyjnego, kup licencję, aby odblokować wszystkie funkcje i uzyskać dostęp do priorytetowego wsparcia technicznego. Pełna dokumentacja API zawiera opisy wszystkich klas i metod omówionych w niniejszym przewodniku.
W razie pytań lub problemów podczas wdrażania pomoc służy zespół wsparcia technicznego. Jeśli chodzi o uwagi dotyczące konkretnych platform, takich jak Blazor Server lub MAUI, dedykowane przewodniki opisują różnice w konfiguracji dla każdego modelu hosta.
Często Zadawane Pytania
Jak mogę dynamicznie generować pliki PDF w ASP.NET Core?
Za pomocą IronPDF można dynamicznie generować pliki PDF w ASP.NET Core bez zapisywania ich na dysku. Umożliwia to strumieniowe przesyłanie plików PDF bezpośrednio do przeglądarek.
Jakie są zalety korzystania z IronPDF do generowania plików PDF?
IronPDF zapewnia potężny silnik renderujący, który umożliwia dynamiczne tworzenie plików PDF bezpośrednio w ramach projektów .NET Core, zapewniając natychmiastowe generowanie plików PDF bez konieczności przechowywania ich po stronie serwera.
Czy IronPDF może służyć do tworzenia faktur i raportów?
Tak, IronPDF nadaje się do tworzenia różnego rodzaju dokumentów, takich jak faktury, raporty i certyfikaty, generowanych na bieżąco w aplikacjach ASP.NET Core.
Czy podczas korzystania z IronPDF konieczne jest przechowywanie danych po stronie serwera?
Nie, IronPDF pozwala generować i przesyłać strumieniowo pliki PDF bezpośrednio do przeglądarek bez konieczności przechowywania ich na serwerze, co sprawia, że jest to rozwiązanie wydajne i szybkie.
Jakie aplikacje mogą skorzystać z generowania plików PDF w locie?
Nowoczesne aplikacje internetowe, zwłaszcza te wymagające tworzenia dokumentów w czasie rzeczywistym, takie jak systemy fakturowania i narzędzia do raportowania, mogą znacznie skorzystać z generowania plików PDF w locie, zapewnianego przez IronPDF.
Czy IronPDF obsługuje projekty .NET Core?
Tak, IronPDF jest w pełni kompatybilny z projektami .NET Core, co pozwala programistom na płynną integrację funkcji generowania plików PDF z ich aplikacjami.

