Add a PDF download to your ASP.NET Core app
Turn an invoice in your ASP.NET Core application into a designed PDF download. Keep the template in HTML and CSS, render it inside your C# process, and return the bytes as an ordinary file response.
This starter includes a .NET 10 Minimal API, a download page, a fictional Northstar Studio invoice, and the fonts used in its design. The FullBleed.DotNet NuGet package calls Fullbleed's native Rust engine; the server needs no Python installation, browser renderer, or external PDF service.

Start with a working download. Install the .NET 10 SDK, extract the ZIP, and open a terminal in its fullbleed-aspnet directory:
dotnet restore --locked-mode
dotnet run -c Release --no-restore -- --urls http://127.0.0.1:5080
Open http://127.0.0.1:5080 and select Download sample PDF. The browser saves invoice-NS-1042.pdf and stays on the page. The lockfile pins FullBleed.DotNet 0.1.8, containing engine 2.5.22.
Return the document through your existing application. The route /invoices/{id}/pdf accepts the sample identifier NS-1042. After rendering succeeds, Program.cs returns:
return Results.File(
pdf, "application/pdf",
fileDownloadName: "invoice-NS-1042.pdf");
ASP.NET's file result supplies the content type and attachment filename. The starter adds Cache-Control: private, no-store to invoice responses. Unknown identifiers return 404; render failures return a generic 500 response.
InvoiceRenderer.cs reads the local template and registers the bundled fonts. Each render creates and disposes its own engine. A missing-glyph diagnostic prevents a document with unsupported text from being returned.
Make the invoice look like your product. Edit Assets/invoice.html and Assets/invoice.css. The sample combines print dimensions, CSS grid, a line-item table, display typography, and a highlighted total. Its fonts travel with the application. To inspect the PDF and a preview rendered from its final bytes, run:
dotnet run -c Release -- --preview output
Open output/invoice.pdf and output/invoice_page1.png. Copy the PNG to Assets/invoice.png and restart the app to update the download page. Review pagination when changing row counts or content; the supplied invoice deliberately fits one page. The CSS reference explains supported print styling.
Connect your records. Replace the fixture lookup with your application's authentication and an account-scoped invoice query before using real customer data. Escape values inserted into HTML, for example with WebUtility.HtmlEncode, and format dates and amounts explicitly. Keep templates and asset paths under application control. Your billing code remains responsible for invoice numbering, tax calculations, and payment state.
The starter allows one native render per server process. A simultaneous request receives 503 with Retry-After: 2. Rendering is synchronous; request cancellation cannot interrupt a native call already in progress. Use an isolated worker when you need hard execution limits, and shared admission controls when scaling across replicas.
Publish the complete app. Build and run its framework-dependent output with:
dotnet publish -c Release --no-restore -o output/publish
dotnet output/publish/FullbleedWeb.dll --urls http://127.0.0.1:5080
Deploy the whole output directory, including native libraries, templates, fonts, and notices. The host needs the .NET 10 ASP.NET Core runtime. The package includes Windows x64, glibc Linux x64, and macOS x64/ARM64 libraries; the guide records deployment boundaries.
Check the evidence. The 11 recorded integration checks use the released package and published application. They cover PDF bytes, text, attachment headers, concurrent requests, missing assets, missing glyphs, and recovery. Desktop keyboard and mobile browser downloads also passed. These checks exercise a synthetic invoice; they do not establish production capacity.
Fullbleed and the example source use MIT; retain the bundled font licenses. Inspect the source README and download manifest, or use the C# quickstart for a console application.