aspnetcore: Tasks returned from JSRuntime.InvokeAsync during OnInitAsync never finishes in preview3
Describe the bug
Tasks returned from JSRuntime.InvokeAsync during second call to OnInitAsync (after prerendering) never finishes.
To Reproduce
Create a new razorcomponents project.
Add a js interop function to Index.cshtml and disable prerendering
<script>
window.interopDuringOnInit = function() {
return "Hello World";
}
</script>
<app></app>
<script src="_framework/components.server.js"></script>
Call js interop during OnAsyncInit in Index.razor
<h1>@Greeting!</h1>
Welcome to your new app.
@functions {
string Greeting;
protected override async Task OnInitAsync()
{
try
{
Console.WriteLine("Calling browser");
Greeting = await JSRuntime.InvokeAsync<string>("interopDuringOnInit");
Console.WriteLine("Returned from browser");
}
catch (Exception ex)
{
Console.WriteLine("Could not invoke interop during OnInit, " + ex.ToString());
}
}
}
When OnInitAsync is called as part of an initial load (prerendering disabled) the task never finishes, This leaves the circuit hanging, and no further events are processed.
If this component is loaded from a IUriHelper.OnLocationChange, the above code works as expected.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 40 (20 by maintainers)
Commits related to this issue
- code done but cannot test because there is a rc bug https://github.com/aspnet/AspNetCore/issues/8274 — committed to stavroskasidis/BlazorContextMenu by deleted user 5 years ago
- Make StartCircuit not block the SignalR message loop. Fixes #8274 — committed to dotnet/aspnetcore by SteveSandersonMS 5 years ago
- Make StartCircuit not block the SignalR message loop. Fixes #8274 — committed to dotnet/aspnetcore by SteveSandersonMS 5 years ago
Has this been fixed yet? I can reproduce this using the latest public version.
This returns a Task that never ends: var cnt = JSRuntime.InvokeAsync<object>(“interop.primes”, n);
This does not return at all, no matter where I call it from. var cnt = await JSRuntime.InvokeAsync<object>(“interop.primes”, n);
Unless I am missing something, this means I can’t get results back from JavaScript at all.
Turns out that in general we don’t block the SignalR message loop. In all cases except one we just hand off to the circuit’s dispatcher and the call is synchronous from SignalR’s perspective.
The one bad case was
StartCircuitwhich did not do this. I’ve fixed this in #8863 by makingCircuitHost.Initializesynchronous. The upstream caller is free to continue handling other incoming messages as soon asCircuitHost.Initializehas dispatched the “init” logic to the renderer’s sync context, because that’s then guaranteed to run and complete before anything else gets handled.I migrated my code to preview 3 and I also ran into this problem. Please fix this!
@davidfowl Thanks for the info. I wasn’t regarding this as a SignalR issue since, even if SignalR did allow concurrent hub method invocations, we’d have had a different problem where you could have received incoming JSInterop calls before the circuit was flagged as started. The underlying false assumption is now fixed in #8863 so neither problem occurs.
Totally agree it would be good for SignalR to have the flexibility to handle parallel messages in general though.
I’ve confirmed that it happens on all of the lifecycle events; the task never returns. Is there a work around that doesn’t break prerendering?
Not only does this happen on
OnInitAsyncbut also onOnParametersSetAsync. Using it on a ButtonClick does return.