skip to Main Content

If you’re encountering issues with loading large PDF files in a Blazor popup, it might be due to limitations in the size of data that can be handled efficiently, especially when using iframe or HTML encoded objects. Loading large files directly into the DOM can sometimes lead to performance issues or even outright failure.

Here is my javascript code block which is called from blazor code behind

Javascript code

function openPdf(base64PdfDoc) {
    "use strict";
    var left = window.screen.width;
    left = left > 0 ? left / 4 : 0;
    let pdfWindow = window.open("", 'winname', 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=no,width=800,height=750, top = 0, left=' + left);
    pdfWindow.document.write(
        "<iframe width='100%' height='100%' src='data:application/pdf;base64, " +
        encodeURI(base64PdfDoc) + "'></iframe>"
    );
}

Javascript called from Backend code

await JsRuntime.InvokeVoidAsync("openPdf", pdfContent);

Trying to bind in html as well but not working

                    <object width="100%" height="100%" data="data:application/pdf;base64,@base64pdfString" type="application/pdf" class="internal"
                    <embed src="data:application/pdf;base64,@base64courierlogpdfString" type="application/pdf" />
</object>

2

Answers


  1. Chosen as BEST ANSWER

    Incorporating the same concept, I've successfully implemented a solution. Since the backend API was returning a response in base64 format, I converted it to a blob and generated a blob URL. Subsequently, I mapped this URL within an iframe to display the content seamlessly.

    function base64ToBlob(base64Data, contentType) {
        contentType = contentType || '';
        var sliceSize = 1024;
        var byteCharacters = atob(base64Data);
        var byteArrays = [];
    
        for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            var slice = byteCharacters.slice(offset, offset + sliceSize);
            var byteNumbers = new Array(slice.length);
            for (var i = 0; i < slice.length; i++) {
                byteNumbers[i] = slice.charCodeAt(i);
            }
            var byteArray = new Uint8Array(byteNumbers);
            byteArrays.push(byteArray);
        }
    
        var blob = new Blob(byteArrays, { type: contentType });
        return blob;
    }
    
    function openPdf(base64Data) {
        var blob = base64ToBlob(base64Data, 'application/pdf');
        var link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        //link.download = filename;
        //link.click();
    
        var left = window.screen.width;
            left = left > 0 ? left / 4 : 0;
            let pdfWindow = window.open("", 'winname', 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=no,width=800,height=750, top = 0, left=' + left);
        pdfWindow.document.write(
            "<iframe width='100%' height='100%' src='" + link.href + "'></iframe>");
    }
    

  2. JavaScript interop is not feasible to pass a very large string. Because Blazor and the underlying System.Text.Json library have a limit on the size of a single JSON value passed through JSInterop, this limit is to prevent performance issues and potential browser crashes.

    So we can bypass this limitation by adding a Controller to Blazor Server Project and then using blobs in javascript, as detailed below.

    Step 1. Prerequisites, add support for controllers in the Blazor project.

    Step 2. The structure of my project.

    enter image description here

    Step 3. Download the pdf.js here. And use it like my project.

    Step 4. pdfViewer.js.

    function showPdfInIframe(pdfUrl) {
        fetch(pdfUrl)
            .then(response => response.blob())
            .then(blob => {
                const url = URL.createObjectURL(blob);
                document.getElementById('pdfIframe').src = url;
            })
            .catch(error => console.error('Error loading the PDF:', error));
    }
    

    Step 5. HomeController.cs.

    using Microsoft.AspNetCore.Mvc;
    
    namespace BlazorApp3.Controllers
    {
        [ApiController]
        [Route("api/[controller]")]
        public class HomeController : Controller
        {
            [HttpGet("{fileName}")]
            public IActionResult Get(string fileName)
            {
                var filePath = Path.Combine("wwwroot", "pdf", fileName);
                if (!System.IO.File.Exists(filePath))
                {
                    return NotFound();
                }
    
                var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                return File(stream, "application/pdf", fileName);
            }
        }
    }
    

    Step 6. PdfDemo.razor.

    @page "/pdfdemo"
    @inject IJSRuntime JSRuntime
    
    
    <h3>PDF.js in Blazor Demo</h3>
    
    
    <iframe id="pdfIframe" style="width:100%; height:600px;" frameborder="0"></iframe>
    
    <button class="btn btn-primary" @onclick="LoadPDF">Load PDF</button>
    
    @code {
        private async Task LoadPDF()
        {
            var fileName = "200MB-TESTFILE.ORG.pdf"; 
            await JSRuntime.InvokeVoidAsync("showPdfInIframe", $"/api/home/{fileName}");
        }
    }
    

    Test Result

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search