Skip to footer content
USING IRONPDF

How to Display PDF in ASP.NET Panel Using IronPDF

Displaying PDF documents within ASP.NET panel controls is a common requirement for document management systems, report viewers, and invoice displays. IronPDF solves this through server-side rendering that eliminates client-side dependencies and works consistently across all browsers and platforms.

When you need to embed PDFs inside your ASP.NET Core web application, the standard approach of relying on browser plugins or client-side libraries creates fragility. Plugin restrictions in enterprise environments, inconsistent browser behavior, and poor mobile support all undermine the user experience. A server-side approach removes every one of those pain points.

IronPDF handles PDF generation and delivery entirely on the server, so the browser receives a standard PDF byte stream with the correct MIME type -- no plugins required, no browser-specific workarounds needed.

IronPDF C# PDF Library homepage banner showing key features including HTML to PDF conversion, PDF editing capabilities, deployment options, and free trial offer

How Does Server-Side PDF Rendering Work in ASP.NET?

IronPDF shifts PDF rendering entirely to the server using a headless Chrome engine. Your controller generates or retrieves a PDF document, converts it to a byte array, and streams it to the browser with an inline Content-Disposition header. The browser's built-in PDF viewer then displays the document inside an <iframe> embedded in your panel.

This fundamental shift eliminates traditional pain points:

  • No Adobe Reader or browser extension required on the client machine
  • Consistent rendering regardless of the user's operating system or browser version
  • Full programmatic control over document content, layout, and styling
  • Works in enterprise environments where IT policies block plugin installations

The library's Chrome rendering engine produces pixel-perfect output from HTML, URL, and raw content sources. You control every aspect of the output -- paper size, margins, headers, footers, and CSS media type -- before the PDF ever reaches the client.

IronPDF also supports cross-platform deployment on Windows, Linux, and macOS servers, making it suitable for cloud-hosted ASP.NET applications running on Azure or AWS, as well as containerized environments using Docker.

IronPDF features overview showing four main categories: Create PDFs, Convert PDFs, Edit PDFs, and Sign and Secure PDFs, with detailed feature lists under each category

How Do You Set Up the NuGet Package?

Open Visual Studio, right-click your project in Solution Explorer, and select Manage NuGet Packages. Search for IronPdf and install it. Alternatively, run this command in the Package Manager Console:

Install-Package IronPdf

You can also use the .NET CLI with dotnet add package IronPdf. Once installed, add using IronPdf; at the top of your controller or service class to access the library's namespace.

For optimal PDF delivery, configure your Program.cs to serve static files and set up routing:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

app.UseStaticFiles();
app.UseRouting();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

app.UseStaticFiles();
app.UseRouting();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();
$vbLabelText   $csharpLabel

The AddControllersWithViews() registration enables both API endpoints and view rendering -- both are needed when you want to serve PDF content through dedicated controller actions and display it inside Razor view panels. For full configuration details, consult the IronPDF API documentation.

How Do You Display a PDF File Directly Inside a Panel?

The core pattern is straightforward: a controller action generates a PDF, converts it to bytes, sets the Content-Disposition header to inline, and returns a File result. An <iframe> in the Razor view points to that endpoint.

Here is a complete controller implementation:

[ApiController]
[Route("api/[controller]")]
public class PdfPanelController : ControllerBase
{
    [HttpGet("display/{documentId}")]
    public IActionResult DisplayPdfInPanel(string documentId)
    {
        var renderer = new ChromePdfRenderer();

        string filename = $"document_{documentId}.pdf";

        var htmlContent = $@"
            <html>
            <head>
                <style>
                    body {{ font-family: Arial, sans-serif; margin: 40px; }}
                    h1 {{ color: #333; }}
                    .content {{ line-height: 1.6; }}
                </style>
            </head>
            <body>
                <h1>Document #{documentId}</h1>
                <div class='content'>
                    <p>This PDF is generated dynamically and displayed inline in your panel.</p>
                    <p>Generated at: {DateTime.Now:yyyy-MM-dd HH:mm:ss}</p>
                </div>
            </body>
            </html>";

        using var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);

        byte[] pdfBytes = pdfDocument.BinaryData;

        Response.Headers.Append("Content-Disposition", $"inline; filename={filename}");

        return File(pdfBytes, "application/pdf");
    }
}
[ApiController]
[Route("api/[controller]")]
public class PdfPanelController : ControllerBase
{
    [HttpGet("display/{documentId}")]
    public IActionResult DisplayPdfInPanel(string documentId)
    {
        var renderer = new ChromePdfRenderer();

        string filename = $"document_{documentId}.pdf";

        var htmlContent = $@"
            <html>
            <head>
                <style>
                    body {{ font-family: Arial, sans-serif; margin: 40px; }}
                    h1 {{ color: #333; }}
                    .content {{ line-height: 1.6; }}
                </style>
            </head>
            <body>
                <h1>Document #{documentId}</h1>
                <div class='content'>
                    <p>This PDF is generated dynamically and displayed inline in your panel.</p>
                    <p>Generated at: {DateTime.Now:yyyy-MM-dd HH:mm:ss}</p>
                </div>
            </body>
            </html>";

        using var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);

        byte[] pdfBytes = pdfDocument.BinaryData;

        Response.Headers.Append("Content-Disposition", $"inline; filename={filename}");

        return File(pdfBytes, "application/pdf");
    }
}
$vbLabelText   $csharpLabel

The ChromePdfRenderer class is the primary entry point for server-side rendering. It accepts HTML content, converts it using a headless Chrome browser, and returns a PdfDocument object. The BinaryData property exposes the raw bytes for streaming.

Setting Content-Disposition to inline is the critical step for panel display. Without it, the browser prompts for a download instead of rendering inside the <iframe>. You can also add headers and footers to every page, or control page orientation and custom margins through RenderingOptions.

To embed this endpoint in a Razor panel, create an <iframe> pointing to the controller route:

@page
@model IndexModel

<div class="container mt-4">
    <div class="card">
        <div class="card-header">
            <h3>PDF Display Panel</h3>
        </div>
        <div class="card-body">
            <div class="pdf-panel" style="height: 600px;">
                <iframe src="/api/PdfPanel/display/12345"
                        width="100%"
                        height="100%"
                        frameborder="0">
                </iframe>
            </div>
        </div>
    </div>
</div>
@page
@model IndexModel

<div class="container mt-4">
    <div class="card">
        <div class="card-header">
            <h3>PDF Display Panel</h3>
        </div>
        <div class="card-body">
            <div class="pdf-panel" style="height: 600px;">
                <iframe src="/api/PdfPanel/display/12345"
                        width="100%"
                        height="100%"
                        frameborder="0">
                </iframe>
            </div>
        </div>
    </div>
</div>
$vbLabelText   $csharpLabel

The <iframe> requests the PDF from your controller endpoint. The browser's built-in PDF viewer takes over from there, displaying the document at full panel width and height without any client-side libraries or plugins.

What Does the Generated PDF Look Like?

Web browser showing a PDF viewer embedded in an ASP.NET application displaying Document #12345 with generation timestamp

How Do You Load PDFs Dynamically with AJAX?

Static <iframe> sources work well for fixed content, but many applications need to load PDFs based on user actions -- clicking a record in a data grid, submitting a form, or selecting a report type. An AJAX-driven approach handles these scenarios without full page reloads.

The controller action accepts a request body and returns the PDF as a base64 string:

[HttpPost("generate")]
public async Task<IActionResult> GenerateDynamicPdf([FromBody] PdfRequestModel request)
{
    try
    {
        var renderer = new ChromePdfRenderer();

        renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 20;
        renderer.RenderingOptions.MarginBottom = 20;
        renderer.RenderingOptions.MarginLeft = 20;
        renderer.RenderingOptions.MarginRight = 20;

        var htmlBuilder = new StringBuilder();
        htmlBuilder.Append("<html><body>");
        htmlBuilder.Append($"<h2>{request.Title}</h2>");
        htmlBuilder.Append($"<div>{request.Content}</div>");

        if (request.IncludeData)
        {
            htmlBuilder.Append("<table border='1' style='width:100%;'>");
            foreach (var item in request.DataItems)
            {
                htmlBuilder.Append($"<tr><td>{item.Key}</td><td>{item.Value}</td></tr>");
            }
            htmlBuilder.Append("</table>");
        }

        htmlBuilder.Append("</body></html>");

        var pdfDocument = await Task.Run(() =>
            renderer.RenderHtmlAsPdf(htmlBuilder.ToString()));

        var base64Pdf = Convert.ToBase64String(pdfDocument.BinaryData);

        return Ok(new { success = true, pdfData = base64Pdf });
    }
    catch (Exception ex)
    {
        return BadRequest(new { success = false, error = ex.Message });
    }
}
[HttpPost("generate")]
public async Task<IActionResult> GenerateDynamicPdf([FromBody] PdfRequestModel request)
{
    try
    {
        var renderer = new ChromePdfRenderer();

        renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 20;
        renderer.RenderingOptions.MarginBottom = 20;
        renderer.RenderingOptions.MarginLeft = 20;
        renderer.RenderingOptions.MarginRight = 20;

        var htmlBuilder = new StringBuilder();
        htmlBuilder.Append("<html><body>");
        htmlBuilder.Append($"<h2>{request.Title}</h2>");
        htmlBuilder.Append($"<div>{request.Content}</div>");

        if (request.IncludeData)
        {
            htmlBuilder.Append("<table border='1' style='width:100%;'>");
            foreach (var item in request.DataItems)
            {
                htmlBuilder.Append($"<tr><td>{item.Key}</td><td>{item.Value}</td></tr>");
            }
            htmlBuilder.Append("</table>");
        }

        htmlBuilder.Append("</body></html>");

        var pdfDocument = await Task.Run(() =>
            renderer.RenderHtmlAsPdf(htmlBuilder.ToString()));

        var base64Pdf = Convert.ToBase64String(pdfDocument.BinaryData);

        return Ok(new { success = true, pdfData = base64Pdf });
    }
    catch (Exception ex)
    {
        return BadRequest(new { success = false, error = ex.Message });
    }
}
$vbLabelText   $csharpLabel

The RenderingOptions block lets you configure paper size, margins, and CSS media type before rendering. According to Microsoft's ASP.NET Core documentation, asynchronous patterns are essential for maintaining responsive interfaces under load. Wrapping the synchronous render call in Task.Run keeps the request thread free while the Chrome engine processes the HTML.

The base64 response lets the JavaScript client update the <iframe> source directly without a page reload:

fetch('/api/PdfPanel/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(requestData)
})
.then(response => response.json())
.then(result => {
    if (result.success) {
        const iframe = document.getElementById('pdf-frame');
        iframe.src = 'data:application/pdf;base64,' + result.pdfData;
    }
});
fetch('/api/PdfPanel/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(requestData)
})
.then(response => response.json())
.then(result => {
    if (result.success) {
        const iframe = document.getElementById('pdf-frame');
        iframe.src = 'data:application/pdf;base64,' + result.pdfData;
    }
});
JAVASCRIPT

This pattern works well for Razor Pages and MVC views alike. For advanced use cases, IronPDF also supports asynchronous rendering natively, so you can use RenderHtmlAsPdfAsync directly instead of Task.Run.

How Do You Handle Different PDF Source Types?

IronPDF can generate PDFs from three primary sources: HTML strings, local HTML files, and external URLs. Each suits different scenarios.

How Do You Convert HTML Templates to PDFs?

Template-based generation is the most common pattern in enterprise ASP.NET applications. You maintain HTML templates with placeholder tokens, inject data at runtime, and render the result:

[HttpGet("from-html")]
public IActionResult GenerateFromHtmlString(string reportType)
{
    var renderer = new ChromePdfRenderer();

    var htmlTemplate = GetHtmlTemplate(reportType);

    var userName = User?.Identity?.Name ?? "Unknown";

    var processedHtml = htmlTemplate
        .Replace("{{DATE}}", DateTime.Now.ToString("yyyy-MM-dd"))
        .Replace("{{USER}}", userName)
        .Replace("{{REPORT_TYPE}}", reportType);

    renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;

    using var pdf = renderer.RenderHtmlAsPdf(processedHtml);

    pdf.SaveAs(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", $"{reportType}.pdf"));

    return File(pdf.BinaryData, "application/pdf");
}

private string GetHtmlTemplate(string reportType)
{
    return @"
        <html>
        <head><title>{{REPORT_TYPE}} Report</title></head>
        <body>
            <h1>{{REPORT_TYPE}} Report</h1>
            <p>Date: {{DATE}}</p>
            <p>User: {{USER}}</p>
            <div>Report content goes here.</div>
        </body>
        </html>";
}
[HttpGet("from-html")]
public IActionResult GenerateFromHtmlString(string reportType)
{
    var renderer = new ChromePdfRenderer();

    var htmlTemplate = GetHtmlTemplate(reportType);

    var userName = User?.Identity?.Name ?? "Unknown";

    var processedHtml = htmlTemplate
        .Replace("{{DATE}}", DateTime.Now.ToString("yyyy-MM-dd"))
        .Replace("{{USER}}", userName)
        .Replace("{{REPORT_TYPE}}", reportType);

    renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;

    using var pdf = renderer.RenderHtmlAsPdf(processedHtml);

    pdf.SaveAs(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", $"{reportType}.pdf"));

    return File(pdf.BinaryData, "application/pdf");
}

private string GetHtmlTemplate(string reportType)
{
    return @"
        <html>
        <head><title>{{REPORT_TYPE}} Report</title></head>
        <body>
            <h1>{{REPORT_TYPE}} Report</h1>
            <p>Date: {{DATE}}</p>
            <p>User: {{USER}}</p>
            <div>Report content goes here.</div>
        </body>
        </html>";
}
$vbLabelText   $csharpLabel

CssMediaType.Print ensures the PDF uses print-specific CSS rules, which typically removes navigation bars, sidebars, and other screen-only elements. This produces cleaner output when your HTML templates are shared between web views and PDF generation. You can also apply custom watermarks or background images for branding. For complex layouts, page break control lets you specify exactly where new pages begin.

What Does HTML Template PDF Output Look Like?

PDF viewer displaying an htmltopdf report with watermarks, showing date 2025-11-18 and 'User: Unknown' text against a crosshatch pattern background

How Do You Generate PDFs from External URLs?

For capturing external web pages -- competitor analysis, regulatory filings, or content from third-party services -- IronPDF can render any publicly accessible URL:

[HttpGet("from-url")]
public async Task<IActionResult> GenerateFromUrl(string encodedUrl)
{
    var url = HttpUtility.UrlDecode(encodedUrl);

    var renderer = new ChromePdfRenderer();

    renderer.RenderingOptions.ViewPortWidth = 1920;
    renderer.RenderingOptions.EnableJavaScript = true;
    renderer.RenderingOptions.WaitFor.RenderDelay(2000);

    using var pdf = await renderer.RenderUrlAsPdfAsync(url);

    Response.Headers.Append("Content-Disposition", "inline; filename=webpage.pdf");

    return File(pdf.BinaryData, "application/pdf");
}
[HttpGet("from-url")]
public async Task<IActionResult> GenerateFromUrl(string encodedUrl)
{
    var url = HttpUtility.UrlDecode(encodedUrl);

    var renderer = new ChromePdfRenderer();

    renderer.RenderingOptions.ViewPortWidth = 1920;
    renderer.RenderingOptions.EnableJavaScript = true;
    renderer.RenderingOptions.WaitFor.RenderDelay(2000);

    using var pdf = await renderer.RenderUrlAsPdfAsync(url);

    Response.Headers.Append("Content-Disposition", "inline; filename=webpage.pdf");

    return File(pdf.BinaryData, "application/pdf");
}
$vbLabelText   $csharpLabel

The ViewPortWidth setting determines how wide the headless browser renders the page before converting to PDF. A 1920-pixel viewport captures modern responsive layouts at desktop resolution. The render delay gives JavaScript-heavy single-page applications time to finish their initialization before the screenshot is taken.

For more advanced capture scenarios, IronPDF supports JavaScript execution control, cookie passing for authenticated pages, and viewport zoom adjustments.

How Do You Manage Memory and Performance?

PDF generation is resource-intensive. Each call to ChromePdfRenderer creates a headless Chrome process, and each PdfDocument object holds the rendered bytes in memory. Proper disposal prevents resource leaks and keeps memory consumption predictable under load.

Always use using statements with PdfDocument:

public IActionResult OptimizedPdfGeneration()
{
    var renderer = new ChromePdfRenderer();
    renderer.RenderingOptions.CreatePdfFormsFromHtml = false;

    var processedHtml = GetHtmlTemplate("report")
        .Replace("{{DATE}}", DateTime.Now.ToString("yyyy-MM-dd"))
        .Replace("{{USER}}", "Test")
        .Replace("{{REPORT_TYPE}}", "Report");

    using var pdf = renderer.RenderHtmlAsPdf(processedHtml);

    byte[] pdfBytes = pdf.BinaryData;
    pdf.SaveAs("output.pdf");

    return File(pdfBytes, "application/pdf");
}
public IActionResult OptimizedPdfGeneration()
{
    var renderer = new ChromePdfRenderer();
    renderer.RenderingOptions.CreatePdfFormsFromHtml = false;

    var processedHtml = GetHtmlTemplate("report")
        .Replace("{{DATE}}", DateTime.Now.ToString("yyyy-MM-dd"))
        .Replace("{{USER}}", "Test")
        .Replace("{{REPORT_TYPE}}", "Report");

    using var pdf = renderer.RenderHtmlAsPdf(processedHtml);

    byte[] pdfBytes = pdf.BinaryData;
    pdf.SaveAs("output.pdf");

    return File(pdfBytes, "application/pdf");
}
$vbLabelText   $csharpLabel

The using statement ensures the PdfDocument object is disposed immediately after you extract the byte array, even if an exception occurs downstream. For applications that generate PDFs frequently, consider these additional strategies:

  • Caching: Store frequently requested PDFs in memory cache or on disk. Use IMemoryCache to cache the byte array keyed by a document identifier and timestamp.
  • Streaming: For very large documents, use PDF memory streams instead of byte arrays to avoid allocating large contiguous memory blocks.
  • Linearization: Enable linearized (fast web view) output so browsers can begin rendering before the full file downloads.
  • Compression: Apply PDF compression to reduce file size when serving documents over constrained network connections.

The IronPDF performance guide covers additional optimization strategies for high-throughput scenarios.

What Does Optimized PDF Output Produce?

PDF document viewer showing an 'Improve Report' with date 2025-11-18 and user 'Test', displayed at 100% zoom with Iron Software watermarks

How Do You Ensure Security and Cross-Browser Compatibility?

Security and reliability both deserve attention before you deploy PDF panel display to production.

Input validation: Always sanitize dynamic content before injecting it into HTML templates. Unsanitized user input rendered through the Chrome engine can expose your server to SSRF and XSS attacks. Use established HTML encoding libraries or restrict accepted characters to a safe allowlist.

Access control: Protect your PDF endpoints behind authentication and authorization middleware. A URL like /api/PdfPanel/display/12345 that returns a document without checking the caller's identity is a data exposure risk. Apply [Authorize] attributes and validate that the authenticated user has permission to access the requested document ID.

MIME type configuration: Always return application/pdf as the content type. Browsers that receive an incorrect MIME type may trigger a download dialog or refuse to render inline. Verify your application's MIME type mappings include PDF if you are also serving static PDF files from wwwroot.

Cross-browser inline display: Modern browsers -- Chrome, Firefox, Edge, and Safari -- all support inline PDF display through the Content-Disposition: inline header. The W3C Content Security Policy specification provides guidance on frame-ancestors directives if your panels embed PDFs from different origins. IronPDF's server-side rendering eliminates most browser rendering inconsistencies because PDF generation happens independently of the client.

Error handling: Wrap PDF generation in try-catch blocks and return meaningful HTTP status codes. A 500 response with no body is difficult to diagnose. Return a structured error object so client-side code can display a user-friendly message rather than a broken <iframe>.

For document security, IronPDF supports password protection and permissions, digital signatures, and PDF/A compliance for archival requirements.

IronPDF cross-platform support diagram showing compatibility with .NET versions, operating systems, development environments, and programming languages including C#, F#, VB.NET, Java, Node.js, and Python

What Are Your Next Steps?

You now have a working pattern for displaying PDFs in ASP.NET panels: install IronPDF, create a controller action that generates a PDF and returns it with Content-Disposition: inline, and embed the endpoint in an <iframe> inside your Razor panel. From there, the AJAX pattern lets you load documents dynamically in response to user actions without page reloads.

Start a free trial of IronPDF to test these patterns in your own project -- no credit card required. The trial includes full access to all features, including HTML-to-PDF rendering, URL capture, and advanced PDF manipulation.

Once you have basic display working, consider these natural extensions:

The IronPDF documentation covers each of these capabilities in depth, with complete code examples and configuration reference.

Frequently Asked Questions

What is the purpose of displaying PDFs in ASP.NET panels?

Displaying PDFs in ASP.NET panels allows developers to integrate PDF documents directly into web applications, creating a seamless user experience for document management, report viewing, or invoice displays.

How can IronPDF help with displaying PDFs in ASP.NET?

IronPDF provides tools that enable developers to effortlessly render and display PDF documents within ASP.NET panels, ensuring smooth integration and a cohesive user interface.

What are the benefits of using IronPDF for displaying PDFs in ASP.NET applications?

Using IronPDF allows for easy PDF integration, reduces development time, and enhances the functionality of ASP.NET applications by providing high-quality PDF rendering within UI controls.

Can IronPDF be used for building document management systems in ASP.NET?

Yes, IronPDF is ideal for building document management systems as it supports seamless PDF display within ASP.NET panels, enhancing the capability to manage and view documents directly on the web.

Is IronPDF compatible with ASP.NET Core for PDF display?

IronPDF is fully compatible with ASP.NET Core, allowing developers to display PDF documents within web applications using panel controls, ensuring modern web integration.

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...

Read More

Iron Support Team

We're online 24 hours, 5 days a week.
Chat
Email
Call Me