Magnus Mårtensson
Microsoft Regional Director, Azure MVP, CEO Loftysoft
Avirag Jain
Director & CTO R Systems
Mahesh Chand
Founder C# Corner, CEO Mindcracker
Chris Gali
CEO & Co-Founder Graphite
Subinder Khurana
Chief Architect StoryProcess, Founder NASSCOM DeepTech Club
Bryan Rishforth
Investor, Chairman Graphite
Bryn Everson
Director Biz Dev Graphite
Raj Tiwari
Digital Transformation Leader, Futurist and Visionary
Joseph Guadagno
Microsoft MVP, Lead Quicken Loans
Nikita Sachdev
Entrepreneur, Blockchain Enthusiast & Advisor, Social Media Influencer
Doug Wagner
COO & Founder Adapt Technical Group
Ritesh Modi
Architect, Senior Evangelist, Cloud Architect
Crystal Wenrick
Director Communications Mindcracker
Allen O’Neill
Microsoft MVP, Consulting Engineer/Architect
Praveen Kumar
CEO MCN Solutions
Chris Love
Founder Love2Dev, Microsoft MVP, Author
Sanjay Vyas
Microsoft Regional Director, Microsoft MVP, Founder & CEO SkillLabs Technologies
Veena Sarda
Deep Learning Consultant, Author
Sekhar Srinivasan
C# Corner MVP, Microsoft Certified Trainer, Pluralsight Author
Lalit Bansal
Founder & CEO - EIY SYS
Navdeep Garg
CEO Revinfotech
Prakash Tripathi
Tech Manager/Leader, Microsoft MVP, Blogger
Bhavna Jain
Breakthrough Consultant
Naveen Sharma
Enterprise Architect, Leadership Coach, Author
Vidya Vrat Agarwal
Principal Architect, Microsoft MVP, Author
Sheetal Agarwal
Founder Clownselors, Medical Clown, Trainer
Abhishek Kant
Founder GTM Catalyst
Vishnu Saran
Founder & CEO VoiceQube
Sandeep Soni
Founder & CEO Deccansoft, Microsoft Certified Trainer
Parveen Malik
AVP InfoSec & Vulnerability Management, Information Security Expert
Nitin Pandit
Microsoft MVP, Developer Evangelist, Author
Niloshima Srivastava
C# Corner MVP, Tech Architect, Trainer, Blogger
Bala Chirtsabesan
Senior Software Engineer at Microsoft, Author
Manoj Mittal
Sr. Technical Architect, C# Corner MVP, Author
Chandni Di
Co-Founder Voice of Slum
Vithal Wadje
Technical Lead, Microsoft MVP, Author
Shivam Ahuja
Founder SkillCircle, Business Mentor
Chervine Bhiwoo
Solution Architect, Microsoft MVP, Author
Saurabh Jain
Vice President Paytm, Founder Fun2Do Labs, Author
Vinay Solanki
Head IoT at Lenovo, Founder IoT-NCR
Anshu kumari
Founder Blockchainkids, Inventor, Trainer
Amit Singal
CEO Startup Buddy
Dev Pratap
Co-Founder & CEO Voice of Slum
Amey Vartak
Technology Consultant, Full Stack Developer, C# Corner MVP, Author
Viswanatha Swamy
Principal Software Engineer, C# Corner MVP, Author
Sanket Verma
Research Engineer @ Ballistics (Forensics) and Chair, PyData Delhi
Sourabh Somani
Lead Developer, Microsoft MVP, Author
Abhishek Mishra
Software Architect, C# Corner MVP, Author
Siddharth Vaghasia
Technical Consultant, C# Corner MVP, Blogger
Bassam Alugili
Senior Software Specialist, Database Expert
S Ravi Kumar
Solution Architect, C# Corner MVP, Author
Sundaram Subramanian
Full Stack Developer, C# Corner MVP, Speaker
Deepesh Somani
Solution Architect, Microsoft MVP, Author
Debasis Saha
Technical Project Manager, C# Corner MVP, Blogger, Author
Vipul Jain
Software Architect, C# Corner MVP, Author
Akshay Patel
Technical Architect, Microsoft Certified Trainer, C# Corner MVP, Author
Stephen Simon
RPA Developer, Evangelist, Author
Vivek Sharma
Founder Kingster636, AR/VR Specialist
Jeetendra Gund
Technical Lead, C# Corner MVP, Author
Sujal Beniwal
AI Enthusiast, Student
M Viknaraj
Microsoft MVP, Azure Architect, Author
Prasham Sabadra
Software Architect, C# Corner MVP, Trainer, Author
Aakash Maurya
Senior Developer, C# Corner MVP, Speaker
Ankit Sharma
Senior Software Engineer, C# Corner MVP, Author
Mangesh Gaherwar
Team Lead, C# Corner MVP, Author
Viral Jain
Technical Consultant, C# Corner MVP, Author
Bhasker Das
Solution Architect, Evangelist
Manish Dwivedi
Associate Project Manager
Ck Nitin
Programmer, Author
Rohit Gupta
Technical Trainer, Author
Manish Tewatia
Full-stack Marketer, UX Designer
Bhavya Gaur
Technical Illustrator
Rohit Tomar
SEO/SMO Expert
Web Track
Cloud & Data Track
Dev Track
Registration & Breakfast
Future of Desktop Apps with JS (ElectronJs)
Nitin Pandit
Building Serverless Microservices Using Microsoft Azure
Vithal Wadje
Innovating RPA: A Robot for Every Person
Stephen Simon
Managing Cloud Storage Accounts using Logic Apps
Viknaraj Manogararajah
Data visualization using Python
Sekhar Srinivasan
Going Cross platform with AR Foundation
Vivek Sharma
Keynote
Managing your Azure dependencies in ASP.NET Core apps using VS
Bala Chirtsabesan
Securing Applications on Intelligent Azure
Abhishek Mishra
Getting started with Blazor the Framework of Future
S Ravi Kumar
Lunch
Build Progressive Web Apps using Angular 9
Debasis Saha
Build and deploy to any platform using Azure DevOps
Chervine Bhiwoo
Deep Dive in Azure Service Bus
Akshay Patel
Build a Native Mobile Application using React Native and JavaScript
Joseph Guadagno
Making sense of Web Job, Web Job SDK and Functions in Azure
Prakash Tripathi
CloudFront Distribution in AWS
Viral Jain
Tea Break
Introduction to PowerBI
Aakash Maurya
Build Advanced SPFx solutions with React and Graph API
Siddharth Vaghasia
Build Business Intelligence Analyst (BIA) Skills
Sundaram Subramanian
Deep dive of Power Platform – AI BUILDER
Prasham Sabadra
Panel 1
What's new in SharePoint development
Vipul Jain
Build a SSO (Single Sign On) based Native JavaScript application with Microsoft Identity within 10 minutes
Manoj Mittal
Panel 2
Applications and working of AI
Veena Sarda
Deploying serverless API's with .Net core 3.0 on AWS & Azure
Amey Vartak
Panel 3
Blockchain with .NET Core (Ark)
Anshu Kumari
Closing Note & Prize Distribution
Dev Track
Cloud Track
Architecture Track
Emerging Tech Track
Registration & Breakfast
Creating Full-Stack Web Apps Using Server-Side Blazor
Ankit Sharma
Real time face recognition with MS Cognitive Services
Niloshima Srivastava
Building Scalable APIs with GraphQL
Jeetendra Gund
Future of development with AI and Blockchain
Navdeep Garg
Debugging Tips and Tricks with Visual Studio 2019
Joseph Guadagno
Azure Containers
Abhishek Kant
Enterprise Architecture
Naveen Sharma
Bot Framework - learn it fast and look like a boss!
Allen O’Neill
Keynote
.Net Core & C# 8 Performance
David McCarter
Working with Azure kubernetes services
Ritesh Modi
Becoming an Architect
Vidyavrat Agarwal
Why Techies Need to Learn Product Management
Saurabh Jain
Lunch
Build a rules engine in .Net Core
Sanjay Vyas
Building CI and CD Pipeline using Azure DevOps
Sandeep Soni
Entity Framework Core - Tips and Tricks, Performance Optimization, and Tuning
Bassam Alugili
Hacking your way into Data Science
Sanket Verma
Speed up your .Net Core Website
Sourabh Somani
Azure
Magnus Mårtensson
Demystifying Open Distro for Elasticsearch
Suman Debnath
Future of Data
Shivam Ahuja
Tea Break
gRPC with C# and .Net Core
Mangesh Gaherwar
Panel 1
Essentials of Cloud security
Parveen Malik
Power platform and Dynamics 365
Deepesh Somani
Microservices - the gRPC Way
Viswanatha Swamy
Panel 2
Reserved
Reserved
Closing Note & Prize Distribution
Building a PDF Generator with QuestPDF in C#
Generating polished PDF documents is a common requirement in modern C# applications. Invoices, delivery dockets, reports, statements, certificates and booking confirmations often need to be produced automatically rather than assembled manually. QuestPDF provides a fluent .NET API for defining document layouts in code, making it a practical option for developers working with ASP.NET Core, Azure Functions, worker services and desktop applications.
The library uses familiar C# concepts such as methods, objects, collections and lambda expressions. Instead of positioning every item with fixed coordinates, you describe the document as a hierarchy of pages, columns, rows, tables, text blocks and images. This approach makes layouts easier to read and maintain as business requirements change.
A PDF generator is especially useful for Australian businesses that issue tax invoices in Australian dollars, display an ABN and account for GST. A solution may also need to support A4 paper, Australian addresses, local phone numbers and dates such as 24/06/2020. These details are straightforward to include when the document is built from structured data.
The example below creates an invoice generator with QuestPDF. It covers project setup, document composition, reusable components, tables, page numbering, Australian business details and deployment considerations. The same patterns can be adapted for conference schedules, speaker profiles, attendance certificates or technical reports.
Choosing QuestPDF For A C# Application
QuestPDF is a code-first PDF document framework for .NET. Its fluent layout model lets you define how content flows across a page, so a long description or table can continue naturally on a second page. This is more flexible than manually drawing text at fixed positions, particularly when invoices contain a variable number of line items.
The library is suitable for ASP.NET Core APIs and background processing. A web endpoint can generate a PDF in memory and return it as a file download, while a scheduled service can save documents to Azure Blob Storage. For a conference platform, the same approach can produce registration confirmations, session schedules and speaker information sheets.
A typical application separates three responsibilities:
- Business services calculate totals and retrieve records.
- A document class describes the PDF layout.
- An API, worker or user interface delivers the generated file.
Keeping these responsibilities separate prevents QuestPDF calls from spreading throughout controllers and domain services. It also makes the layout easier to test and replace if the application later requires a different rendering strategy.
Creating The Project And Configuring Licensing
Create a console application, web API or class library with the .NET SDK, then install QuestPDF from NuGet:
dotnet new console -n InvoicePdfDemo
cd InvoicePdfDemo
dotnet add package QuestPDF
QuestPDF versions can change their licensing and API details, so check the package documentation that matches the version installed by your project. In versions that require an explicit licence selection, configure it during application startup:
using QuestPDF.Infrastructure;
QuestPDF.Settings.License = LicenseType.Community;
The Community licence may apply to eligible individuals, organisations or open-source projects under the publisher’s terms. A commercial Australian company should review the current licence conditions before deploying the generator for paid work. This is a software licence decision, separate from obligations such as GST or the Privacy Act 1988.
Define a model containing the information required by the document:
public record Invoice(
string Number,
DateTime IssueDate,
string BusinessName,
string Abn,
string CustomerName,
string CustomerAddress,
IReadOnlyList<InvoiceLine> Lines);
public record InvoiceLine(
string Description,
decimal Quantity,
decimal UnitPrice);
Using decimal for currency calculations helps avoid the rounding problems associated with binary floating-point types. Keep calculations in the application’s business layer, then pass the final values to the document. This makes it clear how subtotal, GST and total amounts were produced.
Designing A Document With Reusable Components
A QuestPDF document can be represented by a class that implements IDocument. The page definition normally includes a size, margins, default text style, header, content and footer. Australian invoices commonly use A4, which is already supported by the library.
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
public sealed class InvoiceDocument : IDocument
{
private readonly Invoice _invoice;
public InvoiceDocument(Invoice invoice)
{
_invoice = invoice;
}
public DocumentMetadata GetMetadata() => new()
{
Title = $"Invoice {_invoice.Number}",
Author = _invoice.BusinessName
};
public void Compose(IDocumentContainer container)
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(40);
page.DefaultTextStyle(x => x.FontSize(10));
page.Header().Element(ComposeHeader);
page.Content().Element(ComposeContent);
page.Footer()
.AlignCenter()
.Text(text =>
{
text.Span("Page ");
text.CurrentPageNumber();
});
});
}
private void ComposeHeader(IContainer container)
{
container.Row(row =>
{
row.RelativeItem()
.Text(_invoice.BusinessName)
.FontSize(20)
.Bold();
row.ConstantItem(150)
.AlignRight()
.Text($"Invoice {_invoice.Number}");
});
}
}
Reusable methods such as ComposeHeader, ComposeContent and ComposeSummary keep the main page declaration concise. They also allow a consistent visual language across several document types. A shared helper can define colours, border thickness, spacing and typography for invoices, certificates and conference documents.
QuestPDF containers are composable. A Column stacks elements vertically, a Row places them horizontally, and RelativeItem allocates flexible space while ConstantItem reserves a fixed width. This makes a header adapt better to different business names and invoice numbers than hard-coded coordinates.
Building The Invoice Table And Totals
The content can combine customer information, an itemised table and a financial summary. The calculation below assumes that the supplied line prices are before GST and that the invoice uses the Australian standard GST rate. Actual tax treatment varies by product, customer and business circumstance, so the application should obtain its rules from the appropriate accounting or tax source.
private void ComposeContent(IContainer container)
{
decimal subtotal = _invoice.Lines.Sum(line =>
line.Quantity * line.UnitPrice);
decimal gst = Math.Round(subtotal * 0.10m, 2);
decimal total = subtotal + gst;
container.Column(column =>
{
column.Spacing(15);
column.Item().Text(text =>
{
text.Span("Issued: ").SemiBold();
text.Span(_invoice.IssueDate.ToString("dd/MM/yyyy"));
});
column.Item().Text(text =>
{
text.Span("ABN: ").SemiBold();
text.Span(_invoice.Abn);
});
column.Item().Text(text =>
{
text.Span("Bill To: ").SemiBold();
text.Span($"{_invoice.CustomerName}, {_invoice.CustomerAddress}");
});
column.Item().Table(table =>
{
table.ColumnsDefinition(columns =>
{
columns.RelativeColumn(4);
columns.RelativeColumn(1);
columns.RelativeColumn(2);
columns.RelativeColumn(2);
});
table.Header(header =>
{
header.Cell().Element(HeaderCell).Text("Description");
header.Cell().Element(HeaderCell).AlignRight().Text("Qty");
header.Cell().Element(HeaderCell).AlignRight().Text("Unit price");
header.Cell().Element(HeaderCell).AlignRight().Text("Amount");
});
foreach (var line in _invoice.Lines)
{
decimal amount = line.Quantity * line.UnitPrice;
table.Cell().Element(BodyCell).Text(line.Description);
table.Cell().Element(BodyCell).AlignRight()
.Text(line.Quantity.ToString("0.##"));
table.Cell().Element(BodyCell).AlignRight()
.Text(line.UnitPrice.ToString("C2"));
table.Cell().Element(BodyCell).AlignRight()
.Text(amount.ToString("C2"));
}
});
column.Item().AlignRight().Column(summary =>
{
summary.Item().Text($"Subtotal: {subtotal:C2}");
summary.Item().Text($"GST: {gst:C2}");
summary.Item().Text($"Total: {total:C2}").Bold();
});
});
}
private static IContainer HeaderCell(IContainer container) =>
container.Background(Colors.Grey.Lighten2)
.Padding(5)
.DefaultTextStyle(x => x.Bold());
private static IContainer BodyCell(IContainer container) =>
container.BorderBottom(1)
.BorderColor(Colors.Grey.Lighten2)
.Padding(5);
The C2 format uses the process culture. For a service that may run in a different Azure region, explicitly set an Australian culture when formatting money, or use a currency formatter that guarantees the required AUD representation. Culture settings should be tested rather than assumed, especially when a worker runs under an invariant or US-based environment.
A proper invoice may also require payment terms, bank details, a purchase order reference and a note explaining whether prices include GST. Those fields should be modelled explicitly rather than embedded in layout code.
Generating Files And Returning Them From An API
Once the document class is ready, a file can be generated with a single call:
var invoice = new Invoice(
"INV-2020-0042",
new DateTime(2020, 6, 24),
"Harbour Cloud Pty Ltd",
"12 345 678 901",
"Example Customer",
"100 Collins Street, Melbourne VIC 3000",
new List<InvoiceLine>
{
new("Azure consulting", 8, 180m),
new("PDF reporting module", 1, 950m)
});
var document = new InvoiceDocument(invoice);
document.GeneratePdf("invoice-2020-0042.pdf");
For an ASP.NET Core endpoint, generating into a MemoryStream avoids creating temporary files on the web server:
[HttpGet("{number}/pdf")]
public IActionResult Download(string number)
{
Invoice invoice = invoiceService.Get(number);
using var stream = new MemoryStream();
new InvoiceDocument(invoice).GeneratePdf(stream);
return File(
stream.ToArray(),
"application/pdf",
$"invoice-{invoice.Number}.pdf");
}
The endpoint should authorise access to the invoice before generating it. A PDF can contain names, addresses, payment information or other personal data, so access control, logging and storage policies matter under Australian privacy requirements. If documents are stored in Azure Blob Storage, use private containers and short-lived access links rather than publicly accessible URLs.
For users in Sydney, Brisbane, Perth or regional areas, a generated download should behave consistently across desktop browsers and mobile connections. Keep response sizes reasonable, avoid embedding unnecessarily large images and consider asynchronous generation for lengthy reports.
Validating Layout, Accessibility And Australian Requirements
PDF generation should be tested with realistic data rather than a single short invoice. Include long customer names, multiline addresses, zero-value quantities, dozens of line items and descriptions that wrap across multiple lines. QuestPDF’s flow-based layout can handle many of these cases, but a visual test will reveal cramped columns, unexpected page breaks or totals separated from the table.
Use a simple review checklist for each document build:
- Render short, medium and multi-page documents.
- Verify dates, decimal rounding, GST and currency formatting.
- Check headers, footers and page numbers on every page.
- Open the file in multiple PDF viewers and test downloads.
Australian business documents commonly include the supplier’s legal name, ABN, issue date, description, amount and GST information when applicable. Whether an invoice is a valid tax invoice depends on the transaction and business circumstances, so the application should be reviewed with an Australian accountant or tax adviser. A generator should support the required information without presenting itself as a substitute for professional advice.
Accessibility also deserves attention. Use meaningful text instead of images for important labels, maintain readable contrast and avoid relying on colour alone to communicate status. If a document must meet a specific accessibility or archival standard, verify whether the chosen QuestPDF version and downstream PDF processing pipeline support that standard.
Production monitoring should capture generation failures, execution time and document identifiers without recording unnecessary personal information. Load-test large reports, configure sensible request timeouts and decide whether PDF work belongs in a queue. This is particularly useful for a national service operating across Australian time zones, where scheduled invoice batches may run overnight without tying up web requests.
1, CBD, Maharaj Surajmal Road, Near Yamuna Sports Complex, Delhi, 110032
GENERAL QUERIES
Manish Tewatia
manish@csharpcon.com
+91-9718-431-042
TICKET QUERIES
Atul Gupta
conference@csharpcon.com
+91-9910-125-804