.netmauimaui-blazor

BlazorBootstrap PdfViewer loads PDF only once in .NET MAUI Blazor Hybrid app


In a .NET MAUI Blazor Hybrid app a razor component renders a link of links such as:

<NavLink href="@($"PharmakaPdfViewer/{row.Id}")" Match="NavLinkMatch.Prefix">...</NavLink>

Here's the code of the PharmakaPdfViewer component:

@page "/pharmakapdfviewer/{id}"

<h3>PharmakaPdfViewer @Id</h3>

<PdfViewer Class="mb-3" Url="@link" />

@code {
    [Parameter]
    public string? Id { get; set; }

    private string? link = string.Empty;

    protected override async Task OnInitializedAsync()
    {
        var serviceClient = new APIServiceClient();

        var dataRow = await serviceClient.GetDataRowAsync(Int32.Parse(Id));

        link = dataRow.Link;

        await base.OnInitializedAsync();
    }

}

PdfViewer is this Blazor Bootstrap component , which loads the PDF file fetched by the link URL. The value of the link property is set in the overridden OnInitializedAsync, which calls a SOAP web service and gets back the URL of the pdf file corresponding to the provided Id, for example:

https://localhost:44360/Content/Sample.pdf

The first time, everything works fine and the pdf is shown.

But when I navigate back to the list of links and click another (or the same, for that matter), I always get the following error (in the DevTools Console) and the PdfViewer remains empty as shown in the screenshot:

Invalid parameter object: need either .data, .range or .url
Error: Invalid parameter object: need either .data, .range or .url
    at Module.getDocument (https://0.0.0.0/_content/Blazor.Bootstrap/pdfjs-4.0.379.min.js:21:46398)
    at Module.initialize (https://0.0.0.0/_content/Blazor.Bootstrap/blazor.bootstrap.pdf.js:202:11)
    at https://0.0.0.0/_framework/blazor.webview.js:1:3050
    at new Promise (<anonymous>)
    at g.beginInvokeJSFromDotNet (https://0.0.0.0/_framework/blazor.webview.js:1:3007)
    at https://0.0.0.0/_framework/blazor.webview.js:1:48020
    at EventTarget.<anonymous> (<anonymous>:7:62)
    at EmbeddedBrowserWebView.<anonymous> (<anonymous>:1:43835)
   at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
   at Microsoft.JSInterop.JSObjectReferenceExtensions.InvokeVoidAsync(IJSObjectReference jsObjectReference, String identifier, Object[] args)
   at BlazorBootstrap.PdfViewerJsInterop.InitializeAsync(Object objRef, String elementId, Double scale, Double rotation, String url)
   at BlazorBootstrap.PdfViewer.OnAfterRenderAsync(Boolean firstRender)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

PdfViewer unhandled error

Any idea why this is happening and how can it be fixed?

UPDATE:

I chose the following implementation to force the component to re-render without complaining about string.Empty or null:

@if (!string.IsNullOrEmpty(link))
{
    <PdfViewer Class="mb-3" Url="@link" />
}

@code {
    [Parameter]
    public string? Id { get; set; }

    private string? link;

    protected override async Task OnInitializedAsync()
    {
        // Set link to null to force removal of the pdf viewer
        link = null;

        StateHasChanged();

        var serviceClient = new APIServiceClient();

        var dataRow = await serviceClient.GetDataRowAsync(Int32.Parse(Id));

        link = dataRow.Link;        
    }
}

That seems to do the trick.


Solution

  • Invalid parameter object: need either .data, .range or .url

    I can reproduce the error when I set the link as string.Empty. And according to the error message, the link is invalid.

    I see you used the async task to get the Url. So you can try to use StateHasChanged(); after you get the Url:

     protected override async Task OnInitializedAsync()
        {
            var serviceClient = new APIServiceClient();
    
            var dataRow = await serviceClient.GetDataRowAsync(Int32.Parse(Id));
    
            link = dataRow.Link;
            
            StateHasChanged();
        }