COMING SOON: Spring 2026 Release Arrives April 15th
Garry Klooesterman
Senior Technical Content Creator
Published April 02, 2026
Updated April 02, 2026
5 min
Garry Klooesterman
Senior Technical Content Creator

Summary: In this blog, we’ll look at the three main paths for generating PDFs using Blazor and the Apryse SDK: Server-side processing with the .NET SDK (best for power), Client-side WASM with WebViewer (best for privacy and cost), and the DocGen template approach that saves you from writing endless layout code. We’ll also look at an example of how to do this with Blazor Server and the Apryse Server SDK.

If you’ve spent any time in Blazor, you know that the where matters just as much as the what. Because Blazor can live on a server, in a browser (WASM), or in a hybrid MAUI container, generating a PDF isn't a one-size-fits-all task.
The biggest hurdle for most of us is figuring out if we should do the heavy lifting on the backend or try to keep everything in the client’s browser to save on server costs.
In this blog, we’ll look at the different approaches and run through an example using Blazor Server and the Apryse Server SDK.
If you’re running Blazor Server (or the newer Interactive Server mode in .NET 8/9/10), you have direct access to your databases and the full .NET ecosystem.
For this, the Apryse .NET SDK is the standard tool. You initialize it once in your Program.cs file and then call it from your services. A common use case is taking an Office doc and flipping it to a PDF:
Drawing your PDFs with coordinates is a nightmare to maintain. Instead, use a Word document (.docx) as your template. You put tags like {{InvoiceNumber}} or {{Total}} in the document, and the SDK merges a JSON object directly into it.
It’s way more human-friendly. If your branding team wants to change a font or a logo, they just edit the Word file without you having to redeploy your C# code.
If you’re on WebAssembly, you don't have a backend to talk to. In the past, this meant you were stuck, but now you can run the entire Apryse engine in the browser using WASM.
Because this is a JavaScript-heavy operation, you’ll use JS Interop to bridge the gap between your C# logic and the WebViewer UI. It keeps the data on the user's machine, which is a huge win for privacy-sensitive apps.
One thing that catches everyone off guard in Blazor is that you can’t just send a file to the user from a C# method. You have to hand the byte array back to the browser and let JavaScript handle the actual download.
The best way to handle PDFs in Blazor depends entirely on your hosting model. If you have the server resources, the .NET SDK is incredibly fast and reliable. If you're building a massive consumer-facing app and want to save on cloud costs, offloading that work to WebViewer via WASM is a smart move. Either way, try to stick to a template-based workflow, and your future self will thank you when the layout needs to change.
Now we’ll run through an example for generating PDFs in Blazor Server using the Apryse Server SDK. I’ll be using C# for the example, but the code is available in other languages as well, including C++, JavaScript, Python, and more. Let’s get started.
First, we need to get started with the Apryse Server SDK:
Here’s a quick video on getting started if you prefer a visual walkthrough.
Now that we’re set up, let’s look at how to generate PDFs in Blazor Server.
This service uses the Apryse Server SDK for .NET to create a document in memory. Add this code to the PdfService.cs file.
Note: Don’t forget to set replace YOUR_APRYSE_LICENSE_KEY with your trial key.
Add this to the Pages/_Host.cshtml file inside a <script> tag. Blazor cannot push files to a hard drive without a bridge.
Note: If you don't have a _Host.cshtml file, place this script tag inside the <head> or <body> of your App.razor file instead.
Add this line to the Program.cs file, so Blazor knows how to provide the PdfService to the components.
builder.Services.AddScoped<PdfService>();In your .razor page, use the following code to trigger the service and use the JS Interhop helper to prompt the user to download the file.
Having run the code, we should have created a new PDF file from scratch and prompted the user to download the file. The PDF will contain the text “Hello from Blazor Server!”
Is Blazor Server slower for PDFs?
The generation itself is fast but remember that every byte of that PDF has to travel over a SignalR connection if you aren't careful. For huge files, a separate Web API is often a better architecture.
Can I do HTML-to-PDF in Blazor?
Yes. The .NET SDK has a dedicated HTML2PDF module. It’s perfect for taking a dynamic dashboard view and turning it into a static report.
What about Interactive Auto Render mode?
Your code might start on the server and move to the client. The best practice here is to put your PDF logic behind an interface, so your UI doesn't care if it's calling a local WASM engine or a remote Server API.
Do I need a license for the trial?
The trial is fully functional, but you'll need to initialize the SDK with a key. You can grab one from the Apryse portal to get started.
Choosing the right PDF strategy for your Blazor application ultimately comes down to balancing server resources with the user experience.
Whether you opt for the raw power of the Server-Side .NET SDK, the cost-efficiency and privacy of Client-Side WASM, or the maintenance-friendly DocGen template approach, Apryse provides a unified engine that handles the heavy lifting.
By leveraging the examples we’ve walked through, you can focus on building features that matter to your users.
Contact us for any questions and support.
PRODUCTS
Platform Integrations
End User Applications
Popular Content
RESOURCES
using pdftron;
using pdftron.PDF;
using pdftron.SDF;
public async Task<byte[]> OfficeToPdf(string filePath) {
// Ensure PDFNet is initialized with your license key elsewhere
return await Task.Run(() => {
try {
using var doc = new PDFDoc();
// Performs high-quality conversion without MS Office
pdftron.PDF.Convert.OfficeToPDF(doc, filePath, null);
// Returns the serialized PDF as a byte array
return doc.Save(SDFDoc.SaveOptions.e_linearized);
}
catch (pdftron.Common.PDFNetException e) {
// Handle SDK-specific conversion errors
throw new Exception($"PDFNet conversion failed: {e.Message}");
}
});
}using pdftron;
using pdftron.PDF;
using pdftron.SDF;
public class PdfService
{
public string GenerateSimplePdf()
{
// 1. Initialize the SDK with your key from the Apryse Dashboard
PDFNet.Initialize("YOUR_APRYSE_LICENSE_KEY");
try
{
using (PDFDoc doc = new PDFDoc())
{
// 2. Create a new page (Standard Letter Size)
Page page = doc.PageCreate(new Rect(0, 0, 612, 792));
doc.PagePushBack(page);
// 3. Add content using ElementBuilder and ElementWriter
using (ElementBuilder builder = new ElementBuilder())
using (ElementWriter writer = new ElementWriter())
{
writer.Begin(page);
// Create a text element
Font font = Font.Create(doc, Font.StandardType1Font.e_helvetica_bold);
Element element = builder.CreateTextBegin(font, 24);
writer.WriteElement(element);
element = builder.CreateTextRun("Hello from Blazor Server!");
element.SetTextMatrix(1, 0, 0, 1, 50, 700);
writer.WriteElement(element);
writer.WriteElement(builder.CreateTextEnd());
writer.End();
}
// 4. Save to a byte array and convert to Base64 for the browser
byte[] pdfData = doc.Save(SDFDoc.SaveOptions.e_linearized);
return Convert.ToBase64String(pdfData);
}
}
catch (Exception ex)
{
return string.Empty;
}
finally
{
PDFNet.Terminate();
}
}
}window.downloadFile = (fileName, base64String) => {
const link = document.createElement('a');
link.download = fileName;
link.href = 'data:application/pdf;base64,' + base64String;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};@page "/generate-pdf"
@inject PdfService PdfService
@inject IJSRuntime JS
<h3> PDF Generator</h3>
<button class="btn btn-primary" @onclick="DownloadPdf">Generate and Download PDF</button>
@code {
private async Task DownloadPdf()
{
// 1. Call the service to generate the PDF string
var base64Pdf = PdfService.GenerateSimplePdf();
if (!string.IsNullOrEmpty(base64Pdf))
{
// 2. Trigger the JS helper to download the file to the user's computer
await JS.InvokeVoidAsync("downloadFile", "GeneratedReport.pdf", base64Pdf);
}
}
}