Reporting PDF export
Reporting uses the Blazorise PDF engine internally for generation and lets applications choose how PDF previews are rendered.
Examples
PDF Preview
Enable PDF as a preview format and provide aPdfPreviewTemplate to render the generated document with Blazorise PdfViewer or another PDF viewer.
Reporting does not depend on a specific viewer. The example uses the optional Blazorise PdfViewer package and receives the PDF content, data URL, file name, permissions, and download callback through ReportPdfPreviewContext.
The report status bar displays progress for data-source resolution, PDF construction and rendering, preview preparation, and browser download handoff. Handle PdfProgressed to receive the same reusable ReportProgress updates in application code. Indeterminate operations expose no percentage; page rendering exposes measured progress through the Completed and Total values.
Reports can include images and custom fonts in their PDF output. Without additional setup, an image must contain a base64 data URL and a custom font must be supplied as data or as a file that the application can read. If a report instead points to an image or font URL, enable URL loading as described in the Blazorise PDF setup guide.
Insert aggregate
Running total
Insert group
Connect data source
No provider settings defined.
Edit formula
| Item | Formula |
| Description | Select a field, function, or operator to insert it into the formula. |
<Report Data="" Editable PreviewFormats="ReportPreviewFormat.Html | ReportPreviewFormat.Pdf"> <ReportViewer PreviewFormat="ReportPreviewFormat.Html | ReportPreviewFormat.Pdf" DefaultPreviewFormat="ReportPreviewFormat.Pdf" AllowDownload AllowPrint> <PdfPreviewTemplate Context="preview"> <PdfViewerContainer Height="Height.Rem( 48 )"> <PdfViewerToolbar ShowPrinting="@preview.AllowPrint" ShowDownloading="@preview.AllowDownload" /> <PdfViewer Source="@preview.DataUrl" Mode="PdfViewerMode.Continuous" DownloadFileName="@preview.FileName" /> </PdfViewerContainer> </PdfPreviewTemplate> </ReportViewer> <ReportToolbar> <ReportToolbarGroup> <ReportToolbarPanesMenu /> </ReportToolbarGroup> <ReportToolbarGroup> <ReportToolbarItem Command="ReportCommand.PreviewHtml" Caption="HTML Preview" /> <ReportToolbarItem Command="ReportCommand.PreviewPdf" Caption="PDF Preview" /> <ReportToolbarItem Command="ReportCommand.DownloadPdf" Caption="Download PDF" /> </ReportToolbarGroup> <Div Margin="Margin.IsAuto.FromStart"> <ReportToolbarGroup> <ReportToolbarItem Command="ReportCommand.Design" Caption="Design" ShowCaption /> <ReportToolbarItem Command="ReportCommand.Preview" Caption="Preview" ShowCaption /> </ReportToolbarGroup> </Div> </ReportToolbar> <ReportDataSources> <ReportObjectDataSource Name="Invoice" Data="" /> </ReportDataSources> <ReportPage Name="Invoice"> <ReportHeader Name="PDF export header" Height="84"> <ReportText Text="PDF export invoice" X="30" Y="18" Width="240" Height="24" FontSize="20" Bold FontColor="@ReportColors.Blue" /> <ReportText Text="{Customer.Name}" X="30" Y="48" Width="240" Height="18" /> <ReportText Text="{Header.Number}" X="405" Y="48" Width="105" Height="18" TextAlignment="TextAlignment.End" /> </ReportHeader> <ReportPageHeader Name="Column headers" Height="32"> <ReportText Text="Description" X="30" Y="8" Width="270" Height="18" Bold /> <ReportText Text="Total" X="420" Y="8" Width="90" Height="18" Bold TextAlignment="TextAlignment.End" /> </ReportPageHeader> <ReportDetail Name="Invoice lines" Height="30" DataSource="Invoice.Lines"> <ReportField Field="Description" X="30" Y="6" Width="270" Height="18" /> <ReportField Field="Total" Format="@ReportFormats.Currency()" X="420" Y="6" Width="90" Height="18" FontColor="@ReportColors.Green" /> </ReportDetail> <ReportFooter Name="Invoice footer" Height="45"> <ReportLine X="30" Y="6" Width="480" Height="8" Thickness="1" /> <ReportText Text="Invoice total" X="300" Y="18" Width="105" Height="18" Bold /> <ReportField Field="Header.Total" Format="@ReportFormats.Currency()" X="420" Y="18" Width="90" Height="18" Bold FontColor="@ReportColors.Green" /> </ReportFooter> </ReportPage> </Report>
@code { private readonly InvoiceReportModel invoice = new() { Header = new() { Number = "INV-1001", Total = 1240.50m, }, Customer = new() { Name = "Northwind Traders", }, Lines = [ new() { Description = "Implementation workshop", Total = 640.50m }, new() { Description = "Reporting module license", Total = 500.00m }, new() { Description = "Priority support", Total = 100.00m }, ], }; private sealed class InvoiceReportModel { public InvoiceHeaderModel Header { get; set; } public InvoiceCustomerModel Customer { get; set; } public List<InvoiceLineModel> Lines { get; set; } = []; } private sealed class InvoiceHeaderModel { public string Number { get; set; } public decimal Total { get; set; } } private sealed class InvoiceCustomerModel { public string Name { get; set; } } private sealed class InvoiceLineModel { public string Description { get; set; } public decimal Total { get; set; } } }
Backend PDF
Generate a PDF from a saved report in a scheduled job, hosted service, API endpoint, or other backend code. No<Report> component or browser interaction is required.
A ReportDefinition is the saved report design. It describes the pages, bands, elements, formulas, and data-source connections, but it does not persist the actual runtime data. This allows an end user to design the report once while the backend supplies current data each time the report is generated.
Call AddBlazoriseReporting during application startup to register the two services used by this process:
IReportRendererunderstands the report definition. It resolves the report's data sources and converts the report into aPdfDocumentDefinition, which describes the pages and elements that must appear in the PDF.IPdfGeneratortakes that document definition and creates the actual PDF file. It can return the PDF as bytes or write it directly to a stream.
The backend workflow is:
Load the persisted report JSON and deserialize it into a
ReportDefinition.Create
ReportRenderOptionsfor the current run. UseDataSourcesto attach runtime data by the same names used in the designer. For example, theUpcomingItemskey supplies data to the designer data source namedUpcomingItems. Values can be objects, collections,DataTable, orDataSetinstances.DefaultDatais available for a report that uses one default object source.Call
IReportRenderer.RenderAsync. The renderer works on a copy of the saved definition, validates and resolves its data, and applies the same pagination, expressions, running totals, plugins, and row limits as the interactive PDF preview.Pass the returned
PdfDocumentDefinitiontoIPdfGeneratorto produce the PDF bytes or write them to the destination stream.
SQL, CSV, Web API, and custom data sources work slightly differently. Their saved definitions contain the provider type and provider settings, so the renderer can ask the registered provider to load the data. You only need to add one of these sources to ReportRenderOptions.DataSources when you want to supply its data directly instead of loading it through the provider. Use ReportRenderOptions.Parameters for values that a provider needs only for the current run.
IReportRenderer and IPdfGenerator are scoped because they use the data-source providers and other services from the current dependency-injection scope. Controllers, Razor components, and other scoped services can inject them directly. A hosted service is normally a singleton and has no current scope, so it must create an IServiceScope or AsyncServiceScope for each report operation and resolve both services from that scope, as shown below.
using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; using Blazorise.Pdf; using Blazorise.Reporting; using Microsoft.Extensions.DependencyInjection; public sealed class ScheduledReportPdfService { private readonly IServiceScopeFactory scopeFactory; public ScheduledReportPdfService( IServiceScopeFactory scopeFactory ) { this.scopeFactory = scopeFactory; } public async Task GenerateAsync( string reportJson, IReadOnlyList<UpcomingItem> upcomingItems, Stream destination, CancellationToken cancellationToken = default ) { await using AsyncServiceScope scope = scopeFactory.CreateAsyncScope(); IReportRenderer reportRenderer = scope.ServiceProvider.GetRequiredService<IReportRenderer>(); IPdfGenerator pdfGenerator = scope.ServiceProvider.GetRequiredService<IPdfGenerator>(); ReportDefinition definition = ReportJsonSerializer.Deserialize( reportJson ); PdfDocumentDefinition document = await reportRenderer.RenderAsync( definition, new() { DataSources = new Dictionary<string, object> { ["UpcomingItems"] = upcomingItems, }, }, cancellationToken ); await pdfGenerator.GenerateToStreamAsync( document, destination, new() { FileName = "upcoming-items.pdf", }, cancellationToken ); } } public sealed record UpcomingItem( string Title, DateTime StartsAt );
Fonts
Register fonts when PDF export must use the same font family as the designer and HTML preview.
Place font files under wwwroot/fonts, load the font bytes during application startup, and register the font family with Blazorise. Use the same family name from report elements through the FontFamily parameter or from the designer font selector.
byte[] interRegularBytes = await File.ReadAllBytesAsync( "wwwroot/fonts/Inter-Regular.ttf" ); builder.Services .AddBlazorise( options => { options.Fonts.Add( new() { Name = "Inter", DisplayName = "Inter", CssFamily = "\"Inter\", sans-serif", Regular = FontSource.FromBytes( interRegularBytes, FontFormat.TrueType ), } ); } ) .AddBlazoriseReporting();
Browser rendering also needs a matching @font-face rule. This keeps the designer, HTML preview, and PDF export aligned around the same family name.
@font-face {
font-family: "Inter";
src: url("fonts/Inter-Regular.ttf") format("truetype");
font-weight: 400;
font-style: normal;
font-display: swap;
}
API
See the API reference for the parameters, events, methods, and related types available to the components covered on this page.