跳至页脚内容
使用IRONPDF

如何在 Blazor 中显示 PDF

要在 Blazor 应用程序中显示 PDF,请使用 IronPDF 的 PDF 查看器组件,该组件与 Blazor Server 应用程序无缝集成,提供高性能的 PDF 渲染,并具有表单填写、注释和移动支持等功能,而无需第三方浏览器工具。

为什么我需要在 Blazor 中使用 PDF 查看器组件?

在现代 Web 应用程序中显示 PDF 需要一个可靠的查看器组件,该组件的功能超越了浏览器的基本功能。 对于构建 Blazor 应用程序的 .NET 开发人员来说, IronPDF提供了一个有效的PDF 查看器解决方案,可以与您的Blazor Server 应用程序无缝集成。 这样,您无需依赖第三方浏览器工具,即可高性能、高功能地显示 PDF 文档。

在本教程中,我们将探索如何使用 IronPDF 实现 Blazor PDF 查看器,创建一个PDF 查看器组件,该组件可以打开 PDF 文件、处理PDF 内容,并为用户提供直观的界面,以便在桌面和移动设备上显示 PDF。 Chrome渲染引擎确保跨平台显示效果一致。

考虑到浏览器的局限性,使用专用 PDF 查看器组件的必要性就显而易见了。 不同浏览器和平台对原生浏览器 PDF 的支持程度差异很大,导致用户体验不一致。 通过在 Blazor 应用程序中实现自定义 PDF 查看器,您可以完全控制查看体验,确保在所有平台上实现一致的功能。 对于需要符合合规标准安全功能的应用程序而言,这一点尤为重要。

如何使用 IronPDF 显示 PDF 文件?

在实现Blazor PDF查看器之前,您需要安装IronPDF。 通过NuGet将其添加到您的 Blazor Server 应用中:

Install-Package IronPdf

接下来,创建一个新的Blazor应用程序,并确保您已安装最新版本的.NET Core。 将您的 PDF 文件存储在 wwwroot 文件夹中以便轻松访问,或者准备从其他来源(如字节数组或 URL)加载它们。 安装概述部分提供了针对各种部署场景的详细指导。

我需要哪些先决条件?

要成功实现 Blazor PDF 查看器,请确保您已具备以下条件:

  • 您的开发机器上已安装.NET 6.0 或更高版本
  • Visual Studio 2022或带有 C# 扩展的 Visual Studio Code
  • IronPDF 许可证密钥(您可以先免费试用
  • Blazor 组件结构有基本的了解
  • 用于测试的示例 PDF 文件(请将其放在 wwwroot 文件夹中)

对于Windows 部署,请确保您拥有合适的Visual C++ 运行时环境Linux 用户应安装所需的依赖项,而macOS 开发人员需要考虑 Intel 芯片与 Apple Silicon 芯片的兼容性。

我应该把PDF文件保存在哪里?

PDF 文件存储位置对应用程序的性能安全性有显著影响。 对于 Blazor 应用程序,请考虑以下选项:

  • wwwroot 文件夹:非常适合存放不含敏感信息的静态 PDF 文件。 Azure Blob 存储:非常适合需要灵活存储的云应用程序 -数据库以字节数组形式存储:适用于需要访问控制的小型 PDF 文件 -受保护的服务器目录:最适合存放有安全要求的敏感文档 -内存流:最适合使用HTML 转 PDF动态生成 PDF

对于Docker 部署,请考虑容器化存储解决方案AWS Lambda 用户应实施适当的内存管理

如何创建我的第一个 Blazor PDF 查看器组件?

我们来构建一个可以显示PDF文档的基础Blazor PDF查看器组件。 首先,创建一个新的Razor组件:

@page "/pdfviewer"
@rendermode InteractiveServer
@using IronPdf
@inject IJSRuntime JSRuntime
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment WebHostEnvironment
<h3>PDF Viewer Component</h3>
<div>
    <button @onclick="LoadPdfDocument">Open File</button>
    <div id="pdfContainer">
        @if (!string.IsNullOrEmpty(pdfUrl))
        {
            <iframe src="@pdfUrl" style="width:100%; height:600px;"></iframe>
        }
    </div>
</div>
@code {
    private string pdfUrl = "";
    private byte[] pdfData;
    private async Task LoadPdfDocument()
    {
        // Load PDF from file
        var pdfDocument = PdfDocument.FromFile("wwwroot/sample.pdf");
        pdfData = pdfDocument.BinaryData;
        // Create object URL for display
        pdfUrl = await CreateObjectUrl(pdfData);
    }
    private async Task<string> CreateObjectUrl(byte[] data)
    {
        var base64 = Convert.ToBase64String(data);
        return $"data:application/pdf;base64,{base64}";
    }
}
@page "/pdfviewer"
@rendermode InteractiveServer
@using IronPdf
@inject IJSRuntime JSRuntime
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment WebHostEnvironment
<h3>PDF Viewer Component</h3>
<div>
    <button @onclick="LoadPdfDocument">Open File</button>
    <div id="pdfContainer">
        @if (!string.IsNullOrEmpty(pdfUrl))
        {
            <iframe src="@pdfUrl" style="width:100%; height:600px;"></iframe>
        }
    </div>
</div>
@code {
    private string pdfUrl = "";
    private byte[] pdfData;
    private async Task LoadPdfDocument()
    {
        // Load PDF from file
        var pdfDocument = PdfDocument.FromFile("wwwroot/sample.pdf");
        pdfData = pdfDocument.BinaryData;
        // Create object URL for display
        pdfUrl = await CreateObjectUrl(pdfData);
    }
    private async Task<string> CreateObjectUrl(byte[] data)
    {
        var base64 = Convert.ToBase64String(data);
        return $"data:application/pdf;base64,{base64}";
    }
}
Imports IronPdf
Imports Microsoft.AspNetCore.Hosting
Imports Microsoft.AspNetCore.Components
Imports Microsoft.JSInterop

@page "/pdfviewer"
@rendermode InteractiveServer

@inject IJSRuntime JSRuntime
@inject IWebHostEnvironment WebHostEnvironment

<h3>PDF Viewer Component</h3>
<div>
    <button @onclick="LoadPdfDocument">Open File</button>
    <div id="pdfContainer">
        @If Not String.IsNullOrEmpty(pdfUrl) Then
            <iframe src="@pdfUrl" style="width:100%; height:600px;"></iframe>
        End If
    </div>
</div>

@code
    Private pdfUrl As String = ""
    Private pdfData As Byte()

    Private Async Function LoadPdfDocument() As Task
        ' Load PDF from file
        Dim pdfDocument = PdfDocument.FromFile("wwwroot/sample.pdf")
        pdfData = pdfDocument.BinaryData
        ' Create object URL for display
        pdfUrl = Await CreateObjectUrl(pdfData)
    End Function

    Private Async Function CreateObjectUrl(data As Byte()) As Task(Of String)
        Dim base64 = Convert.ToBase64String(data)
        Return $"data:application/pdf;base64,{base64}"
    End Function
End Code
$vbLabelText   $csharpLabel

这段代码创建了一个简单的 PDF 查看器组件,该组件加载PDF 文档并使用 iframe 显示它。 LoadPdfDocument方法从 wwwroot 文件夹读取 PDF 文件并将其转换为字节数组。 CreateObjectUrl方法随后将此字节数组转换为 iframe 可以显示的数据 URL,从而允许用户查看已加载的 PDF 文档。 这种方法适用于各种 PDF 版本,并支持UTF-8 编码

组件如何加载 PDF 文件?

该组件利用IronPDF 的文档加载功能高效地读取 PDF 文件。 当用户点击"打开文件"按钮时, LoadPdfDocument方法:

  1. 使用PdfDocument.FromFile加载 PDF 文件
  2. 从加载的 PDF 文档中提取二进制数据 3.转换为 Base64格式以兼容浏览器。 4.创建浏览器可以直接渲染的数据 URL

这种方法既能确保在不同浏览器上的兼容性,又能保持 PDF 显示的高性能。 该组件可以处理各种纸张尺寸页面方向

显示 PDF 文件时常见的问题有哪些?

在 Blazor 中实现 PDF 查看器时,开发人员经常会遇到以下挑战:

如需排查具体问题,请查阅快速故障排除指南联系工程支持

输出

! Blazor PDF 查看器组件的屏幕截图,显示了一个包含"什么是 PDF?"内容的示例 PDF,其中显示了导航控件、缩放选项和"打开文件"按钮。

如何实现 JavaScript 互操作以改善显示效果?

为了更好地控制PDF内容的显示,我们可以使用JavaScript函数来处理PDF查看器的功能:

@page "/pdf-jsinterop"
@rendermode InteractiveServer
@using IronPdf
@inject IJSRuntime JSRuntime
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment WebHostEnvironment
<h3>IronPDF JavaScript Interop Viewer</h3>
<p>Displays PDF using JavaScript's Blob/ObjectURL capabilities.</p>
@if (!string.IsNullOrEmpty(ErrorMessage))
{
    <div class="alert alert-danger">Error: @ErrorMessage</div>
}
<div id="@documentId" style="border: 1px solid #ccc; width: 100%; min-height: 600px;">
    Loading PDF...
</div>
@code {
    private string documentId = Guid.NewGuid().ToString();
    private string ErrorMessage = string.Empty;
    private bool pdfLoaded = false;
    // Hold the reference to the loaded JavaScript module
    private IJSObjectReference? jsModule;
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && !pdfLoaded)
        {
            try
            {
                // 1. Asynchronously load the JavaScript file as a module
                // This guarantees the script is loaded before the next line executes.
                jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import",
                    "./pdfViewerInterop.js");
                await LoadPdfWithJavaScript();
                pdfLoaded = true;
            }
            catch (Exception ex)
            {
                ErrorMessage = $"Failed to load JS module or execute: {ex.Message}";
            }
            finally
            {
                StateHasChanged();
            }
        }
    }
    private async Task LoadPdfWithJavaScript()
    {
        if (jsModule is null) return; // Should never happen if the module loads successfully
        try
        {
            var pdfPath = Path.Combine(WebHostEnvironment.WebRootPath, "sample.pdf");
            if (!File.Exists(pdfPath))
            {
                ErrorMessage = $"File not found: {pdfPath}";
                return;
            }
            var pdf = PdfDocument.FromFile(pdfPath);
            var stream = new MemoryStream(pdf.BinaryData);
            // 2. Invoke the function using the module reference
            // Note: We only pass the function name here.
            await jsModule.InvokeVoidAsync("displayPdf",
                documentId, stream.ToArray());
        }
        catch (Exception ex)
        {
            ErrorMessage = $"Failed to load PDF or invoke JS: {ex.Message}";
        }
    }
    // IMPORTANT: Dispose of the module when the component is removed
    public async ValueTask DisposeAsync()
    {
        if (jsModule is not null)
        {
            await jsModule.DisposeAsync();
        }
    }
}
@page "/pdf-jsinterop"
@rendermode InteractiveServer
@using IronPdf
@inject IJSRuntime JSRuntime
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment WebHostEnvironment
<h3>IronPDF JavaScript Interop Viewer</h3>
<p>Displays PDF using JavaScript's Blob/ObjectURL capabilities.</p>
@if (!string.IsNullOrEmpty(ErrorMessage))
{
    <div class="alert alert-danger">Error: @ErrorMessage</div>
}
<div id="@documentId" style="border: 1px solid #ccc; width: 100%; min-height: 600px;">
    Loading PDF...
</div>
@code {
    private string documentId = Guid.NewGuid().ToString();
    private string ErrorMessage = string.Empty;
    private bool pdfLoaded = false;
    // Hold the reference to the loaded JavaScript module
    private IJSObjectReference? jsModule;
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && !pdfLoaded)
        {
            try
            {
                // 1. Asynchronously load the JavaScript file as a module
                // This guarantees the script is loaded before the next line executes.
                jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import",
                    "./pdfViewerInterop.js");
                await LoadPdfWithJavaScript();
                pdfLoaded = true;
            }
            catch (Exception ex)
            {
                ErrorMessage = $"Failed to load JS module or execute: {ex.Message}";
            }
            finally
            {
                StateHasChanged();
            }
        }
    }
    private async Task LoadPdfWithJavaScript()
    {
        if (jsModule is null) return; // Should never happen if the module loads successfully
        try
        {
            var pdfPath = Path.Combine(WebHostEnvironment.WebRootPath, "sample.pdf");
            if (!File.Exists(pdfPath))
            {
                ErrorMessage = $"File not found: {pdfPath}";
                return;
            }
            var pdf = PdfDocument.FromFile(pdfPath);
            var stream = new MemoryStream(pdf.BinaryData);
            // 2. Invoke the function using the module reference
            // Note: We only pass the function name here.
            await jsModule.InvokeVoidAsync("displayPdf",
                documentId, stream.ToArray());
        }
        catch (Exception ex)
        {
            ErrorMessage = $"Failed to load PDF or invoke JS: {ex.Message}";
        }
    }
    // IMPORTANT: Dispose of the module when the component is removed
    public async ValueTask DisposeAsync()
    {
        if (jsModule is not null)
        {
            await jsModule.DisposeAsync();
        }
    }
}
Imports System
Imports System.IO
Imports System.Threading.Tasks
Imports IronPdf
Imports Microsoft.AspNetCore.Components
Imports Microsoft.AspNetCore.Components.Web
Imports Microsoft.JSInterop
Imports Microsoft.AspNetCore.Hosting

@page "/pdf-jsinterop"
@rendermode InteractiveServer

@inject IJSRuntime JSRuntime
@inject IWebHostEnvironment WebHostEnvironment

<h3>IronPDF JavaScript Interop Viewer</h3>
<p>Displays PDF using JavaScript's Blob/ObjectURL capabilities.</p>
@if Not String.IsNullOrEmpty(ErrorMessage) Then
    <div class="alert alert-danger">Error: @ErrorMessage</div>
End If
<div id="@documentId" style="border: 1px solid #ccc; width: 100%; min-height: 600px;">
    Loading PDF...
</div>

@code
    Private documentId As String = Guid.NewGuid().ToString()
    Private ErrorMessage As String = String.Empty
    Private pdfLoaded As Boolean = False
    ' Hold the reference to the loaded JavaScript module
    Private jsModule As IJSObjectReference

    Protected Overrides Async Function OnAfterRenderAsync(firstRender As Boolean) As Task
        If firstRender AndAlso Not pdfLoaded Then
            Try
                ' 1. Asynchronously load the JavaScript file as a module
                ' This guarantees the script is loaded before the next line executes.
                jsModule = Await JSRuntime.InvokeAsync(Of IJSObjectReference)("import", "./pdfViewerInterop.js")
                Await LoadPdfWithJavaScript()
                pdfLoaded = True
            Catch ex As Exception
                ErrorMessage = $"Failed to load JS module or execute: {ex.Message}"
            Finally
                StateHasChanged()
            End Try
        End If
    End Function

    Private Async Function LoadPdfWithJavaScript() As Task
        If jsModule Is Nothing Then Return ' Should never happen if the module loads successfully
        Try
            Dim pdfPath = Path.Combine(WebHostEnvironment.WebRootPath, "sample.pdf")
            If Not File.Exists(pdfPath) Then
                ErrorMessage = $"File not found: {pdfPath}"
                Return
            End If
            Dim pdf = PdfDocument.FromFile(pdfPath)
            Dim stream = New MemoryStream(pdf.BinaryData)
            ' 2. Invoke the function using the module reference
            ' Note: We only pass the function name here.
            Await jsModule.InvokeVoidAsync("displayPdf", documentId, stream.ToArray())
        Catch ex As Exception
            ErrorMessage = $"Failed to load PDF or invoke JS: {ex.Message}"
        End Try
    End Function

    ' IMPORTANT: Dispose of the module when the component is removed
    Public Async Function DisposeAsync() As ValueTask Implements IAsyncDisposable.DisposeAsync
        If jsModule IsNot Nothing Then
            Await jsModule.DisposeAsync()
        End If
    End Function
End Code
$vbLabelText   $csharpLabel

将此JavaScript函数添加到您的wwwroot文件夹中的JavaScript文件中:

export function displayPdf(elementId, data) {
    // 1. Create a Blob from the byte array data
    const blob = new Blob([new Uint8Array(data)],
        { type: 'application/pdf' });
    // 2. Create a temporary URL for the Blob
    const url = URL.createObjectURL(blob);
    // 3. Find the container element
    const container = document.getElementById(elementId);
    if (!container) return;
    // 4. Clear any previous content
    container.innerHTML = '';
    // 5. Create and configure the iframe
    const iframe = document.createElement('iframe');
    iframe.src = url;
    iframe.style.width = '100%';
    iframe.style.height = '600px';
    iframe.style.border = 'none';
    // 6. Append the iframe to the container
    container.appendChild(iframe);
}
export function displayPdf(elementId, data) {
    // 1. Create a Blob from the byte array data
    const blob = new Blob([new Uint8Array(data)],
        { type: 'application/pdf' });
    // 2. Create a temporary URL for the Blob
    const url = URL.createObjectURL(blob);
    // 3. Find the container element
    const container = document.getElementById(elementId);
    if (!container) return;
    // 4. Clear any previous content
    container.innerHTML = '';
    // 5. Create and configure the iframe
    const iframe = document.createElement('iframe');
    iframe.src = url;
    iframe.style.width = '100%';
    iframe.style.height = '600px';
    iframe.style.border = 'none';
    // 6. Append the iframe to the container
    container.appendChild(iframe);
}
The provided code is JavaScript, not C#. Therefore, it cannot be directly converted to VB.NET. However, if you have a C# code snippet that you would like to convert to VB.NET, please provide it, and I will assist you with the conversion.
$vbLabelText   $csharpLabel

这个JavaScript函数从PDF数据创建一个blob并生成一个对象URL。 然后,它动态创建一个iframe元素并将其附加到容器。 这种方法可以让你更好地控制PDF 页面的显示方式,并更好地管理 PDF 查看器组件的生命周期。 该技术支持JavaScript 渲染和复杂文档的自定义渲染延迟

为什么我应该使用 JavaScript 互操作而不是直接显示?

JavaScript 互操作为 Blazor 中的PDF 渲染提供了几个优势:

这种互操作方法还支持自定义 JavaScript 执行消息监听器,以适应高级场景。

JavaScript 互操作何时能提升性能?

在以下情况下,JavaScript 互操作性可显著提高性能

对于批量操作,可考虑使用并行处理;对于并发生成 PDF,可考虑使用多线程

如何处理 JavaScript 错误?

妥善的错误处理机制可确保可靠的PDF查看体验。 实施以下策略:

try {
    // Check if the browser supports required features
    if (!window.Blob || !window.URL) {
        throw new Error("Browser doesn't support required PDF viewing features");
    }
    // Validate PDF data before processing
    if (!data || data.length === 0) {
        throw new Error("Invalid PDF data received");
    }
    // Monitor memory usage for large files
    if (data.length > 50 * 1024 * 1024) { // 50MB threshold
        console.warn("Large PDF detected, performance may be affected");
    }
} catch (error) {
    console.error("PDF viewing error:", error);
    // Fallback to server-side rendering
}
try {
    // Check if the browser supports required features
    if (!window.Blob || !window.URL) {
        throw new Error("Browser doesn't support required PDF viewing features");
    }
    // Validate PDF data before processing
    if (!data || data.length === 0) {
        throw new Error("Invalid PDF data received");
    }
    // Monitor memory usage for large files
    if (data.length > 50 * 1024 * 1024) { // 50MB threshold
        console.warn("Large PDF detected, performance may be affected");
    }
} catch (error) {
    console.error("PDF viewing error:", error);
    // Fallback to server-side rendering
}
Try
    ' Check if the browser supports required features
    If Not window.Blob OrElse Not window.URL Then
        Throw New Exception("Browser doesn't support required PDF viewing features")
    End If
    ' Validate PDF data before processing
    If data Is Nothing OrElse data.length = 0 Then
        Throw New Exception("Invalid PDF data received")
    End If
    ' Monitor memory usage for large files
    If data.length > 50 * 1024 * 1024 Then ' 50MB threshold
        Console.Warn("Large PDF detected, performance may be affected")
    End If
Catch error As Exception
    Console.Error.WriteLine("PDF viewing error: " & error.ToString())
    ' Fallback to server-side rendering
End Try
$vbLabelText   $csharpLabel

为了实现完整的错误跟踪,请实施自定义日志记录并监控渲染超时

输出

IronPDF JavaScript 互操作查看器界面显示了一个 PDF 文档,其中包含"什么是 PDF?"的内容,演示了 JavaScript Blob/ObjectURL PDF 渲染功能。

如何从不同来源加载PDF文件?

您的Blazor PDF查看器可以从各种来源检索和显示PDF文档:

private async Task LoadFromUrl()
{
    var client = new HttpClient();
    var response = await client.GetAsync("___PROTECTED_URL_116___");
    var stream = await response.Content.ReadAsStreamAsync();
    var pdfDocument = new PdfDocument(stream);
    await DisplayPdfContent(pdfDocument);
}
private async Task LoadFromHtmlContent()
{
    var renderer = new ChromePdfRenderer();
    var htmlContent = "<h1>Generated PDF</h1>";
    var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);
    await DisplayPdfContent(pdfDocument);
}
private async Task DisplayPdfContent(PdfDocument document)
{
    var data = document.BinaryData;
    pdfUrl = $"data:application/pdf;base64,{Convert.ToBase64String(data)}";
}
private async Task LoadFromUrl()
{
    var client = new HttpClient();
    var response = await client.GetAsync("___PROTECTED_URL_116___");
    var stream = await response.Content.ReadAsStreamAsync();
    var pdfDocument = new PdfDocument(stream);
    await DisplayPdfContent(pdfDocument);
}
private async Task LoadFromHtmlContent()
{
    var renderer = new ChromePdfRenderer();
    var htmlContent = "<h1>Generated PDF</h1>";
    var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);
    await DisplayPdfContent(pdfDocument);
}
private async Task DisplayPdfContent(PdfDocument document)
{
    var data = document.BinaryData;
    pdfUrl = $"data:application/pdf;base64,{Convert.ToBase64String(data)}";
}
Private Async Function LoadFromUrl() As Task
    Dim client = New HttpClient()
    Dim response = Await client.GetAsync("___PROTECTED_URL_116___")
    Dim stream = Await response.Content.ReadAsStreamAsync()
    Dim pdfDocument = New PdfDocument(stream)
    Await DisplayPdfContent(pdfDocument)
End Function

Private Async Function LoadFromHtmlContent() As Task
    Dim renderer = New ChromePdfRenderer()
    Dim htmlContent = "<h1>Generated PDF</h1>"
    Dim pdfDocument = renderer.RenderHtmlAsPdf(htmlContent)
    Await DisplayPdfContent(pdfDocument)
End Function

Private Async Function DisplayPdfContent(document As PdfDocument) As Task
    Dim data = document.BinaryData
    pdfUrl = $"data:application/pdf;base64,{Convert.ToBase64String(data)}"
End Function
$vbLabelText   $csharpLabel

这些方法演示了如何使用 HTTPS 从 URL 加载 PDF 文件、如何将 HTML 内容转换为 PDF以及如何显示生成的 PDF 内容。 LoadFromUrl方法从远程位置检索 PDF 文档,而LoadFromHtmlContent展示了如何动态地将 HTML 转换为 PDF ,从而为 Blazor PDF 查看器组件获取其内容的方式提供了灵活性。 Chrome渲染引擎确保转换准确。

其他信息来源包括:

考虑将 DOCX 转换为 PDF以用于 Microsoft Word 文档,以及将图像转换为 PDF以用于照片存档。

我应该选择哪种数据源?

请根据以下因素选择您的PDF源:

来源类型 最适合 表现 安全性
本地文件 静态内容 出色的
网址 外部文件 良好 语言
HTML转换 动态报表 变量 高的
BLOB 存储 企业应用 出色的 高的
内存流 临时PDF 出色的 高的

对于HTML 文件转换,请考虑使用基本 URL以正确加载资源。 ZIP 文件源提供捆绑内容选项。

从 URL 加载时如何处理网络错误?

实现基于URL的PDF加载的可靠错误处理:

private async Task<PdfDocument> LoadFromUrlWithRetry(string url, int maxRetries = 3)
{
    for (int i = 0; i < maxRetries; i++)
    {
        try
        {
            using var client = new HttpClient();
            client.Timeout = TimeSpan.FromSeconds(30);

            var response = await client.GetAsync(url);
            response.EnsureSuccessStatusCode();

            var stream = await response.Content.ReadAsStreamAsync();
            return new PdfDocument(stream);
        }
        catch (HttpRequestException ex) when (i < maxRetries - 1)
        {
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i))); // Exponential backoff
        }
    }
    throw new Exception($"Failed to load PDF from {url} after {maxRetries} attempts");
}
private async Task<PdfDocument> LoadFromUrlWithRetry(string url, int maxRetries = 3)
{
    for (int i = 0; i < maxRetries; i++)
    {
        try
        {
            using var client = new HttpClient();
            client.Timeout = TimeSpan.FromSeconds(30);

            var response = await client.GetAsync(url);
            response.EnsureSuccessStatusCode();

            var stream = await response.Content.ReadAsStreamAsync();
            return new PdfDocument(stream);
        }
        catch (HttpRequestException ex) when (i < maxRetries - 1)
        {
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i))); // Exponential backoff
        }
    }
    throw new Exception($"Failed to load PDF from {url} after {maxRetries} attempts");
}
Imports System
Imports System.Net.Http
Imports System.Threading.Tasks

Private Async Function LoadFromUrlWithRetry(url As String, Optional maxRetries As Integer = 3) As Task(Of PdfDocument)
    For i As Integer = 0 To maxRetries - 1
        Try
            Using client As New HttpClient()
                client.Timeout = TimeSpan.FromSeconds(30)

                Dim response = Await client.GetAsync(url)
                response.EnsureSuccessStatusCode()

                Dim stream = Await response.Content.ReadAsStreamAsync()
                Return New PdfDocument(stream)
            End Using
        Catch ex As HttpRequestException When i < maxRetries - 1
            Await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i))) ' Exponential backoff
        End Try
    Next
    Throw New Exception($"Failed to load PDF from {url} after {maxRetries} attempts")
End Function
$vbLabelText   $csharpLabel

对于已认证的来源,实现HTTP请求标头并处理TLS登录。 考虑使用cookie 管理基于会话的访问。

HTML 转 PDF 转换在什么情况下最有用?

HTML 转 PDF在以下情况下表现出色:

使用CSS 支持响应式设计,并使用Web 字体实现一致的排版。

使用HTML内容输出

IronPDF 测试界面演示了如何成功地从 HTML 内容生成 PDF,顶部显示了从 URL 加载或从 HTML 生成的选项。

如何为我的PDF阅读器添加交互功能?

通过交互式功能改进您的 PDF 查看器:

@code {
    private int currentPage = 1;
    private int totalPages;
    private string rotationClass = "";
    private async Task NavigateToPage(int page)
    {
        currentPage = page;
        await JSRuntime.InvokeVoidAsync("navigateTo", page);
    }
    private void RotateCounterclockwise()
    {
        // Counterclockwise switch orientation
        rotationClass = "rotate-270";
    }
    private async Task PrintPdf()
    {
        await JSRuntime.InvokeVoidAsync("printDocument", documentId);
    }
    private async Task DownloadPdf()
    {
        var fileName = "document.pdf";
        await JSRuntime.InvokeVoidAsync("downloadFile", 
           pdfData, fileName);
    }
}
@code {
    private int currentPage = 1;
    private int totalPages;
    private string rotationClass = "";
    private async Task NavigateToPage(int page)
    {
        currentPage = page;
        await JSRuntime.InvokeVoidAsync("navigateTo", page);
    }
    private void RotateCounterclockwise()
    {
        // Counterclockwise switch orientation
        rotationClass = "rotate-270";
    }
    private async Task PrintPdf()
    {
        await JSRuntime.InvokeVoidAsync("printDocument", documentId);
    }
    private async Task DownloadPdf()
    {
        var fileName = "document.pdf";
        await JSRuntime.InvokeVoidAsync("downloadFile", 
           pdfData, fileName);
    }
}
Imports System.Threading.Tasks

Private currentPage As Integer = 1
Private totalPages As Integer
Private rotationClass As String = ""

Private Async Function NavigateToPage(page As Integer) As Task
    currentPage = page
    Await JSRuntime.InvokeVoidAsync("navigateTo", page)
End Function

Private Sub RotateCounterclockwise()
    ' Counterclockwise switch orientation
    rotationClass = "rotate-270"
End Sub

Private Async Function PrintPdf() As Task
    Await JSRuntime.InvokeVoidAsync("printDocument", documentId)
End Function

Private Async Function DownloadPdf() As Task
    Dim fileName As String = "document.pdf"
    Await JSRuntime.InvokeVoidAsync("downloadFile", pdfData, fileName)
End Function
$vbLabelText   $csharpLabel

这段代码增加了PDF 页面之间的导航、旋转功能(包括逆时针旋转)以及打印 PDF 的功能。 下载功能允许用户将 PDF 文件保存到本地。 这些功能将您的基本 PDF 查看器转变为一个高效的查看器,内置工具栏,为处理 PDF 文档的用户提供基本功能。 建议添加页码书签,方便导航。

用户最期待哪些功能?

现代PDF阅读器应包含以下基本功能:

高级功能可能包括文本提取图像提取PDF 转 HTML 转换

如何高效地实现页面导航?

高效的页面导航需要改进渲染效果

private async Task<string> RenderSpecificPage(int pageNumber)
{
    var pdfDocument = PdfDocument.FromFile("document.pdf");
    // Extract single page for faster rendering
    var singlePagePdf = pdfDocument.CopyPage(pageNumber - 1);

    // Convert to image for preview
    var imageData = singlePagePdf.RasterizeToImageFiles("preview_*.png", 150);

    return Convert.ToBase64String(imageData[0]);
}
private async Task<string> RenderSpecificPage(int pageNumber)
{
    var pdfDocument = PdfDocument.FromFile("document.pdf");
    // Extract single page for faster rendering
    var singlePagePdf = pdfDocument.CopyPage(pageNumber - 1);

    // Convert to image for preview
    var imageData = singlePagePdf.RasterizeToImageFiles("preview_*.png", 150);

    return Convert.ToBase64String(imageData[0]);
}
Private Async Function RenderSpecificPage(pageNumber As Integer) As Task(Of String)
    Dim pdfDocument = PdfDocument.FromFile("document.pdf")
    ' Extract single page for faster rendering
    Dim singlePagePdf = pdfDocument.CopyPage(pageNumber - 1)

    ' Convert to image for preview
    Dim imageData = singlePagePdf.RasterizeToImageFiles("preview_*.png", 150)

    Return Convert.ToBase64String(imageData(0))
End Function
$vbLabelText   $csharpLabel

对于大型文档,请实施分页符并考虑拆分 PDF以提高性能。 使用缩略图进行视觉导航。

下载功能的最佳实践是什么?

实现安全便捷的下载功能

-对文件名进行清理,以防止安全问题 -添加元数据以更好地组织

  • 对大文件实现压缩 -跟踪下载量以进行分析
  • 如有需要,可添加水印 -设置适当的权限

考虑满足存档需求的PDF/A 合规性要求和满足可访问性的PDF/UA合规性要求。

输出

这是一个功能齐全的 PDF 查看器组件,采用 Blazor 构建,显示文档导航控件、100% 缩放功能以及自定义操作按钮,包括"加载 PDF 文件"、"打印"、"下载"和"旋转"选项。

如何处理PDF表单的填写和注释?

对于带有表单字段注释的PDF 文档,IronPDF 提供可靠的支持:

private async Task ProcessFormFields(
{
    var pdfDocument = PdfDocument.FromFile("form.pdf");
    foreach (var field in pdfDocument.Form.Fields)
    {
        if (field.Type == PdfFormFieldType.Text)
        {
            field.Value = "User Input";
        }
    }
    // Enable form filling in viewer
    var modifiedPdf = pdfDocument.BinaryData;
    await DisplayPdfContent(pdfDocument);
}
private async Task ProcessFormFields(
{
    var pdfDocument = PdfDocument.FromFile("form.pdf");
    foreach (var field in pdfDocument.Form.Fields)
    {
        if (field.Type == PdfFormFieldType.Text)
        {
            field.Value = "User Input";
        }
    }
    // Enable form filling in viewer
    var modifiedPdf = pdfDocument.BinaryData;
    await DisplayPdfContent(pdfDocument);
}
Option Strict On



Private Async Function ProcessFormFields() As Task
    Dim pdfDocument = PdfDocument.FromFile("form.pdf")
    For Each field In pdfDocument.Form.Fields
        If field.Type = PdfFormFieldType.Text Then
            field.Value = "User Input"
        End If
    Next
    ' Enable form filling in viewer
    Dim modifiedPdf = pdfDocument.BinaryData
    Await DisplayPdfContent(pdfDocument)
End Function
$vbLabelText   $csharpLabel

这样,您就可以在 Blazor PDF 查看器组件中启用表单填写功能,允许用户直接在浏览器中与表单字段进行交互。 代码遍历PDF文档中的表单字段并可以编程设置值,非常适合需要动态表单填写功能的应用程序。 支持的功能包括数字签名文本注释

我可以支持哪些类型的表单字段?

IronPDF 支持所有表单字段类型

  • 用于用户输入和数据录入的文本字段
  • 用于布尔选择的复选框
  • 用于互斥选择的单选按钮
  • 预定义选项的下拉列表
  • 用于身份验证的数字签名字段
  • 用于评论的多行文本区域
  • 时间数据的日期选择器

高级功能包括用于企业安全的HSM 签名版本历史记录跟踪。

如何保存用户输入的表单数据?

实现可靠的表单数据持久化

private async Task SaveFormData()
{
    var pdfWithFormData = PdfDocument.FromFile("filled-form.pdf");

    // Extract form data
    var formData = new Dictionary<string, string>();
    foreach (var field in pdfWithFormData.Form.Fields)
    {
        formData[field.Name] = field.Value;
    }

    // Save to database or JSON
    var json = System.Text.Json.JsonSerializer.Serialize(formData);
    await File.WriteAllTextAsync("form-data.json", json);

    // Flatten form to prevent further editing
    pdfWithFormData.Form.Flatten();
    pdfWithFormData.SaveAs("form-submission.pdf");
}
private async Task SaveFormData()
{
    var pdfWithFormData = PdfDocument.FromFile("filled-form.pdf");

    // Extract form data
    var formData = new Dictionary<string, string>();
    foreach (var field in pdfWithFormData.Form.Fields)
    {
        formData[field.Name] = field.Value;
    }

    // Save to database or JSON
    var json = System.Text.Json.JsonSerializer.Serialize(formData);
    await File.WriteAllTextAsync("form-data.json", json);

    // Flatten form to prevent further editing
    pdfWithFormData.Form.Flatten();
    pdfWithFormData.SaveAs("form-submission.pdf");
}
Private Async Function SaveFormData() As Task
    Dim pdfWithFormData = PdfDocument.FromFile("filled-form.pdf")

    ' Extract form data
    Dim formData As New Dictionary(Of String, String)()
    For Each field In pdfWithFormData.Form.Fields
        formData(field.Name) = field.Value
    Next

    ' Save to database or JSON
    Dim json = System.Text.Json.JsonSerializer.Serialize(formData)
    Await File.WriteAllTextAsync("form-data.json", json)

    ' Flatten form to prevent further editing
    pdfWithFormData.Form.Flatten()
    pdfWithFormData.SaveAs("form-submission.pdf")
End Function
$vbLabelText   $csharpLabel

请考虑专业表单的表单验证字段管理

何时应该使用程序化表单填写,何时应该使用交互式表单填写?

根据具体用例选择合适的方法:

方法 使用时机 好处
程序化 预先填充已知数据 更快、更稳定、更自动化
交互的 需要用户输入 灵活、即时的验证
杂交种 部分数据可用 兼具两种方法的优点

提交后考虑将表格展平,以防止篡改。 为了安全起见,请使用PDF文件清理功能

输出

示例展示了 PDF 查看器组件的表单填写功能,说明用户如何直接在浏览器中与 PDF 表单进行交互。

如何提高大型PDF文件的性能?

为了确保在显示 PDF 文件时(尤其是显示大型 PDF 文件时)拥有高性能

private async Task LoadLargePdf()
{
    const int chunkSize = 1024 * 1024; // 1MB chunks
    var pdfPath = "largefile.pdf";
    using (var fileStream = File.OpenRead(pdfPath))
    {
        var buffer = new byte[chunkSize];
        var chunks = new List<byte[]>();
        int bytesRead;
        while ((bytesRead = await fileStream.ReadAsync(buffer)) > 0)
        {
            var chunk = new byte[bytesRead];
            Array.Copy(buffer, chunk, bytesRead);
            chunks.Add(chunk);
        }
        // Process chunks for display
        await ProcessPdfChunks(chunks);
    }
}
private async Task LoadLargePdf()
{
    const int chunkSize = 1024 * 1024; // 1MB chunks
    var pdfPath = "largefile.pdf";
    using (var fileStream = File.OpenRead(pdfPath))
    {
        var buffer = new byte[chunkSize];
        var chunks = new List<byte[]>();
        int bytesRead;
        while ((bytesRead = await fileStream.ReadAsync(buffer)) > 0)
        {
            var chunk = new byte[bytesRead];
            Array.Copy(buffer, chunk, bytesRead);
            chunks.Add(chunk);
        }
        // Process chunks for display
        await ProcessPdfChunks(chunks);
    }
}
Private Async Function LoadLargePdf() As Task
    Const chunkSize As Integer = 1024 * 1024 ' 1MB chunks
    Dim pdfPath As String = "largefile.pdf"
    Using fileStream = File.OpenRead(pdfPath)
        Dim buffer(chunkSize - 1) As Byte
        Dim chunks As New List(Of Byte())()
        Dim bytesRead As Integer
        Do
            bytesRead = Await fileStream.ReadAsync(buffer, 0, buffer.Length)
            If bytesRead > 0 Then
                Dim chunk(bytesRead - 1) As Byte
                Array.Copy(buffer, chunk, bytesRead)
                chunks.Add(chunk)
            End If
        Loop While bytesRead > 0
        ' Process chunks for display
        Await ProcessPdfChunks(chunks)
    End Using
End Function
$vbLabelText   $csharpLabel

这种方法分块加载大型 PDF 文件,防止内存问题,即使处理大型 PDF 文档也能确保流畅的性能。 在移动设备或资源有限的系统上处理 PDF 文件时,它尤其有用。 考虑实施内存泄漏预防策略。

其他优化策略包括:

-线性化以实现更快的网页浏览速度 -压缩以减小文件大小 -并行处理多个PDF文件

对于Docker 环境,改进容器配置。 在AWS Lambda中,要谨慎管理内存分配

文件大小达到什么程度需要分块加载?

考虑根据以下阈值进行分块加载:

文件大小 装载策略 内存影响
小于 5MB 直接装载 最小化
5-20MB 可选分块 缓和
20-50MB 推荐分块 重要的
大于 50MB 需要分块 批判的

对于大型输出文件,实施适当的压缩策略

如何监控内存使用情况?

实施内存监控以获得最佳性能

private async Task<bool> CheckMemoryBeforeLoad(long fileSize)
{
    var memoryInfo = GC.GetTotalMemory(false);
    var availableMemory = GC.GetTotalMemory(true);

    // Conservative estimate: file size * 3 for processing overhead
    var requiredMemory = fileSize * 3;

    if (requiredMemory > availableMemory * 0.8) // 80% threshold
    {
        // Trigger garbage collection
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        // Re-check after cleanup
        availableMemory = GC.GetTotalMemory(true);
        return requiredMemory <= availableMemory * 0.8;
    }

    return true;
}
private async Task<bool> CheckMemoryBeforeLoad(long fileSize)
{
    var memoryInfo = GC.GetTotalMemory(false);
    var availableMemory = GC.GetTotalMemory(true);

    // Conservative estimate: file size * 3 for processing overhead
    var requiredMemory = fileSize * 3;

    if (requiredMemory > availableMemory * 0.8) // 80% threshold
    {
        // Trigger garbage collection
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        // Re-check after cleanup
        availableMemory = GC.GetTotalMemory(true);
        return requiredMemory <= availableMemory * 0.8;
    }

    return true;
}
Private Async Function CheckMemoryBeforeLoad(fileSize As Long) As Task(Of Boolean)
    Dim memoryInfo = GC.GetTotalMemory(False)
    Dim availableMemory = GC.GetTotalMemory(True)

    ' Conservative estimate: file size * 3 for processing overhead
    Dim requiredMemory = fileSize * 3

    If requiredMemory > availableMemory * 0.8 Then ' 80% threshold
        ' Trigger garbage collection
        GC.Collect()
        GC.WaitForPendingFinalizers()
        GC.Collect()

        ' Re-check after cleanup
        availableMemory = GC.GetTotalMemory(True)
        Return requiredMemory <= availableMemory * 0.8
    End If

    Return True
End Function
$vbLabelText   $csharpLabel

监控初始渲染性能,并根据需要进行性能故障排除

何时应该考虑使用服务器端渲染?

在以下情况下,服务器端渲染会变得有利:

对于IIS 部署,请配置相应的应用程序池。 Azure Functions需要特定的部署设置

如何为受密码保护的PDF文件实施安全措施?

处理受密码保护的PDF文件时:

private async Task LoadSecurePdf(string password)
{
    var pdfDocument = PdfDocument.FromFile("secure.pdf", password);
    if (pdfDocument != null)
    {
       var headers = new Dictionary<string, string>
        {
            {"X-Frame-Options", "SAMEORIGIN"},
            {"Content-Security-Policy", "default-src 'self'"}
        };
        await DisplayPdfContent(pdfDocument);
    }
}
private async Task LoadSecurePdf(string password)
{
    var pdfDocument = PdfDocument.FromFile("secure.pdf", password);
    if (pdfDocument != null)
    {
       var headers = new Dictionary<string, string>
        {
            {"X-Frame-Options", "SAMEORIGIN"},
            {"Content-Security-Policy", "default-src 'self'"}
        };
        await DisplayPdfContent(pdfDocument);
    }
}
Private Async Function LoadSecurePdf(password As String) As Task
    Dim pdfDocument = PdfDocument.FromFile("secure.pdf", password)
    If pdfDocument IsNot Nothing Then
        Dim headers = New Dictionary(Of String, String) From {
            {"X-Frame-Options", "SAMEORIGIN"},
            {"Content-Security-Policy", "default-src 'self'"}
        }
        Await DisplayPdfContent(pdfDocument)
    End If
End Function
$vbLabelText   $csharpLabel

此代码演示了如何在保持安全性的同时,通过正确的标头配置来加载受密码保护的 PDF 文档。 考虑使用数字签名来提高身份验证的有效性。

如何安全地处理PDF密码?

遵循以下最佳实践,实现安全的密码管理:

-切勿以明文或客户端代码形式存储密码 使用安全的输入方法并进行适当的验证

  • 对敏感文档实施会话超时机制
  • 对密码传输应用加密 -记录访问尝试以进行安全审计 使用后清除内存中的密码

考虑在企业环境中使用Kerberos 身份验证确保符合 CVE 安全要求

我应该考虑哪些额外的安全标头?

使用完整的页眉提高 PDF 查看器的安全性:

private void ConfigureSecurityHeaders(HttpResponse response)
{
    response.Headers.Add("X-Content-Type-Options", "nosniff");
    response.Headers.Add("X-Frame-Options", "DENY");
    response.Headers.Add("Content-Security-Policy", 
        "default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none'");
    response.Headers.Add("Referrer-Policy", "no-referrer");
    response.Headers.Add("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
}
private void ConfigureSecurityHeaders(HttpResponse response)
{
    response.Headers.Add("X-Content-Type-Options", "nosniff");
    response.Headers.Add("X-Frame-Options", "DENY");
    response.Headers.Add("Content-Security-Policy", 
        "default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none'");
    response.Headers.Add("Referrer-Policy", "no-referrer");
    response.Headers.Add("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
}
Private Sub ConfigureSecurityHeaders(response As HttpResponse)
    response.Headers.Add("X-Content-Type-Options", "nosniff")
    response.Headers.Add("X-Frame-Options", "DENY")
    response.Headers.Add("Content-Security-Policy", 
                         "default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none'")
    response.Headers.Add("Referrer-Policy", "no-referrer")
    response.Headers.Add("Permissions-Policy", "camera=(), microphone=(), geolocation=()")
End Sub
$vbLabelText   $csharpLabel

实施PDF 清理,以删除潜在的恶意内容并编辑敏感信息

客户端解密和服务器端解密分别何时适用?

根据安全需求选择解密方法:

解密类型 使用案例 安全级别
客户端 公开文件
服务器端 敏感数据 高的
杂交种 混合内容 语言

为了最大限度提高安全性,始终在服务器端执行解密,并将解密后的内容安全地传输到客户端。 为满足长期存档需求,实施PDF/A 合规性

Blazor PDF 显示有哪些关键要点?

使用 IronPDF 实现 Blazor PDF 查看器,可以为开发人员提供在 Web 应用程序中显示 PDF 的完整解决方案。 从基本显示到表单填写注释等高级功能,IronPDF 的PDF 查看器组件提供了专业应用程序所需的功能。

所示示例演示了如何创建一个可靠的 Blazor PDF 查看器,该查看器可以处理各种 PDF 源,提供交互式功能,并保持高性能。 无论您是构建简单的文档查看器还是复杂的文档管理系统,IronPDF 与Blazor Server 应用程序的集成都能轻松实现专业的 PDF 查看功能。 Chrome渲染引擎可确保跨平台呈现一致的效果。

使用 IronPDF 进行 Blazor PDF 显示的主要优势包括:

-跨平台兼容性,渲染效果一致

针对特定部署场景,IronPDF 支持AzureAWSDocker和传统Windows环境。 该库还可以与F#VB.NET应用程序集成。

准备好实现您自己的PDF查看器了吗? 立即开始 IronPDF 的免费试用,获取完整的文档演示应用程序开发者支持,以便在 Blazor 应用程序中创建有效的 PDF 查看体验。 快速入门指南可帮助您立即上手,而代码示例则演示了实际应用。

常见问题解答

如何在Blazor应用中使用IronPDF显示PDF?

IronPDF提供全面的API,允许在Blazor应用中渲染和显示PDF。通过集成IronPDF,您可以轻松实现一个强大的PDF查看组件。

使用IronPDF进行Blazor PDF查看有哪些优势?

使用IronPDF进行Blazor PDF查看带来诸如处理表单字段、创建互动查看器以及在您的应用程序中无缝渲染高质量PDF等好处。

在Blazor中使用IronPDF处理PDF中的表单字段是否可能?

是的,IronPDF允许您在Blazor应用中处理和操作PDF文档中的表单字段,提供增强的互动性和用户参与度。

IronPDF是否可用于创建Blazor中的互动PDF查看器?

绝对可以。IronPDF提供工具在Blazor中创建互动PDF查看器,启用诸如表单处理和动态内容显示的功能。

IronPDF为Blazor中的PDF操作提供了哪些功能?

IronPDF提供PDF渲染、表单字段处理、文本提取和页面操作等功能,使其成为Blazor PDF操作的一个多功能选择。

在 C# 中比较两个 PDF 文件(开发者指南)提供了使用 IronPDF 高效比较 PDF 文档的指南,涵盖其必要性、设置 IronPDF 库、读取和解析PDF、执行比较及最佳实践。

IronPDF通过提供流畅的渲染、互动功能和稳健的PDF文档处理来提升Blazor应用中的PDF查看体验。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。