Streamlining .NET Invoice PDFs

Automating PDF invoice creation in .NET shouldn’t feel like wrestling with command-line tools or juggling raw HTML. InvoiceGenerator brings together Razor templating, IronPdf rendering, and idiomatic dependency-injection wiring into one cohesive library. Below, we unpack each layer so you can plug it into your application with confidence.
Overview
InvoiceGenerator.Core
is a NuGet package that helps you generate elegant, typed PDF invoices with just a few lines of code. It supports:
Razor view templates (
.cshtml
)IronPdf rendering
Dependency injection
Custom configuration options
Cross-platform support
🔧 Why I Built It
Many .NET teams build invoices using either static HTML templates or overcomplicated reporting tools.
Problems with those approaches:
Lack of customisability
No DI integration
Complex to maintain
So, I created a solution that integrates clean architecture, DI, and Razor templating using modern .NET practices.
🧠 High-Level Architecture
sequenceDiagram
participant App as Your .NET App
participant Services as IServiceProvider
participant InvGen as IInvoiceGenerator
participant PdfGen as InvoicePdfGenerator
participant Razor as IRazorViewToStringRenderer
participant View as Razor Template (e.g. Views/InvoiceReport.cshtml)
participant Engine as IronPdfGenerator
participant IronPdf as IronPdf.ChromePdfRenderer
App->>Services: GetRequiredService<IInvoiceGenerator>()
Services-->>App: InvoicePdfGenerator
App->>InvGen: GenerateAsync(invoice)
InvGen->>PdfGen: GenerateAsync(invoice)
PdfGen->>PdfGen: ValidateInvoice(invoice)
PdfGen->>Razor: RenderViewToStringAsync(TemplatePath, invoice)
Razor->>View: Compile & Bind Razor View
View-->>Razor: HTML string
Razor-->>PdfGen: HTML content
PdfGen->>Engine: GeneratePdf(html)
Engine->>IronPdf: RenderHtmlAsPdf(html)
IronPdf-->>Engine: PdfDocument
Engine-->>PdfGen: byte[] PDF
PdfGen-->>App: byte[] PDF
🧩 Usage Example
var services = new ServiceCollection()
.AddInvoiceGenerator(options =>
{
options.DefaultPageSize = InvoiceGeneratorOptions.PageSizes.A4;
options.DefaultOrientation = InvoiceGeneratorOptions.Orientations.Portrait;
options.DefaultDocumentTitle = "Test Invoice";
})
.BuildServiceProvider();
var generator = services.GetRequiredService<IInvoiceGenerator>();
var invoice = InvoiceFactory.Create();
byte[] pdfBytes = await generator.GenerateAsync(invoice);
File.WriteAllBytes("Invoice.pdf", pdfBytes);
💡 Under the Hood: How It Works
1. AddInvoiceGenerator
– Configurable DI Extension
This method sets up everything:
Loads Razor rendering service
Configures IronPdf
Registers
IInvoiceGenerator
services.AddScoped<IPdfGenerator>(sp => new IronPdfGenerator(logger)
{
PageSize = "A4",
Orientation = "Portrait"
});
You can also:
Set a Razor view path (
TemplatePath
)Provide an IronPdf license key
2. InvoicePdfGenerator
– The Core Engine
This is the main implementation of IInvoiceGenerator
. It:
Validates the
Invoice
objectRenders Razor HTML using the provided model
Converts that HTML to PDF using IronPdf
string html = await _razorRenderer.RenderViewToStringAsync(_templatePath, invoice);
byte[] pdfData = _pdfGenerator.GeneratePdf(html);
You can override the Razor view path like this:
invoiceGenerator.TemplatePath = "Views/CustomInvoice.cshtml";
3. Razor Rendering (RazorViewToStringRenderer
)
Renders .cshtml
files to HTML strings using RazorLight.
You get full freedom to:
Customize layout
Add logos, tables, styles
Use
@model Invoice
in views
Edit@model Invoice
<h1>Invoice #: @Model.Number</h1>
<p>Total: @Model.Total @Model.CurrencyCode</p>
4. PDF Generation (IronPdfGenerator
)
Uses IronPdf.ChromePdfRenderer
to convert rendered HTML to PDF:
renderer.RenderHtmlAsPdf(html);
Supports:
A4, Letter, Legal, etc.
Portrait / Landscape
Custom margins
Custom titles
Also logs PDF size and diagnostic info via ILogger
.
🔍 Config Options
InvoiceGeneratorOptions
lets you customize:
Option | Description | Default |
PageSize | A4, Letter, Legal, etc. | "A4" |
Orientation | Portrait or Landscape | "Portrait" |
MarginMm | Margin in millimeters | 20 |
CustomTemplatePath | Path to your Razor .cshtml file | Views/InvoiceReport.cshtml |
IronPdfLicenseKey | License key (or read from config) | (optional) |
UseAppSettings | Load from appsettings.json | true |
🔐 Validation Built-in
Before generating any invoice, we validate:
📅 Due date ≥ Issue date
🧾 At least one line item
🏢 Seller and customer addresses
Invalid invoice? You’ll get a ValidationException
.
🧪 Real Example – Multi-Currency Invoices
await GenerateAndSaveInvoice(invoiceGenerator, InvoiceFactory.Create(), "USD_Invoice.pdf");
await GenerateAndSaveInvoice(invoiceGenerator, InvoiceFactory.CreateEuroInvoice(), "EUR_Invoice.pdf");
await GenerateAndSaveInvoice(invoiceGenerator, InvoiceFactory.CreateGbpInvoice(), "GBP_Invoice.pdf");
Each invoice PDF will be cleanly formatted, typed, and ready to share or email.
🧠 Lessons Learned
Razor + IronPdf is a powerful combo for document generation.
Validating data before rendering = fewer runtime surprises.
Abstracting services through interfaces made testing and extending painless.
📦 NuGet + GitHub
📦 NuGet: InvoiceGenerator.Core
🧑💻 GitHub: github.com/sgr-0007/InvoiceGenerator.Core
✅ Currently 514+ downloads!
🛠️ Contributions Welcome!
This is an active project, I’d love your feedback, issues, or pull requests.
Have an idea? Need to support more paper sizes or multi-page layouts? Fork away or reach out!
🙌 Final Thoughts
Building InvoiceGenerator.Core
was about making invoicing flexible, testable, and production-friendly.
Whether you're building:
B2B apps,
Admin dashboards,
Finance portals,
This library gives you clean, repeatable PDF generation with modern .NET practices.
Subscribe to my newsletter
Read articles from Sagar HS directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Sagar HS
Sagar HS
Software engineer with 4 + years delivering high-performance .NET APIs, polished React front-ends, and hands-off CI/CD pipelines. Hackathon quests include AgroCropProtocol, a crop-insurance DApp recognised with a World coin pool prize and ZK Memory Organ, a zk-SNARK privacy prototype highlighted by Torus at ETH-Oxford. Recent experiments like Fracture Log keep me exploring AI observability.