user9402642
user9402642

Reputation: 135

Blazor UriHelper.NavigateTo is calling the page twice

I created a new Blazor Server Side Application in Preview 8. When I call the UriHelper.NavigateTo to go to the counter page from the Index.razor page, the counter page is called twice.

In the Index.razor page I have this code:

@code{

    protected async override Task OnInitializedAsync()
    {
        UriHelper.NavigateTo("/counter");
    }

}

Then in the counter page I added the following code with a breakpoint in it:

protected override void OnInitialized()
{

}

My expectation is to call the counter page only one time when the NavigateTo calls the counter route in the Index.razor

Upvotes: 7

Views: 9120

Answers (2)

dani herrera
dani herrera

Reputation: 51665

This behavior is because the pre-render feature. Notice that, when you are on counter page (loaded for twice), if you click on Home, only one execution is fired:

enter image description here

Summarizing:

When pre-render is enabled (by default), the prerended page's OnInitializedAsync is called for twice by design. For this reason, your redirect statement is executed for twice.

To test is I wrote this code on index OnInitializedAsync:

@page "/"
@inject IUriHelper UriHelper

<h1>Hello, world!</h1>

Welcome to your new app.

@code{

    protected async override Task OnInitializedAsync()
    {
        System.Console.WriteLine("_*   ");
        System.Console.WriteLine("_**************************");
        System.Console.WriteLine("_***** Pre render ******");
        System.Console.WriteLine("_**************************");
        System.Console.WriteLine("_   ");
        return;
    }
}

And I call the page using pre-render and from the app (without prerender). Noticed that when I force reload (prerended) the OnInitializedAsync is executed for twice:

enter image description here

Learn more about render modes.

Upvotes: 6

enet
enet

Reputation: 45626

Update due to a comment by dani herrera:

The life cycle method OnInitializedAsync is called twice, but the counter @page component is called once only. This behavior is by design. The first time OnInitializedAsync is executed is when server-side Blazor app is being pre-rendering, during which time, JSInterop is not available, and thus calling UriHelper.NavigateTo("/counter"); triggers an error. The following code snippet describe how Blazor currently treats such cases:

protected override void NavigateToCore(string uri, bool forceLoad)
        {
            Log.RequestingNavigation(_logger, uri, forceLoad);

            if (_jsRuntime == null)
            {
                var absoluteUriString = ToAbsoluteUri(uri).ToString();
                throw new NavigationException(absoluteUriString);
            }

            _jsRuntime.InvokeAsync<object>(Interop.NavigateTo, uri, forceLoad);
        }

See more here. As you may realize, the counter @page component is not called, and an exception is raised.

After pre-rendering has completed, client-side SignalR establishes a connection to the server, and your app is rendered. This time (second time the method OnInitializedAsync is called) UriHelper.NavigateTo("/counter"); is properly executed, and we are happily navigated to the counter page (first time)

You may use the method OnAfterRender as a workaround, and you should verify whether a connection with the server has already been established by SignalR; that is the pre-rendering process has completed.

@page "/"
@using Microsoft.JSInterop
@inject IComponentContext ComponentContext
@inject IJSRuntime jsRuntime

<p>Navigate to the counter component.</p>

@code{

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (!ComponentContext.IsConnected) return;

         UriHelper.NavigateTo("/counter");
    }
}

Hope this helps...

Upvotes: 4

Related Questions