Blazor 服务器端应用程序在重新加载期间抛出“System.InvalidOperationException:此时无法发出 JavaScript 互操作调用。...”

2023-11-23

我在 blazor 应用程序的其中一个页面中实现了一个文件放置区域,该区域是使用 javascript 运行时接口进行处理的。为了避免内存泄漏,我有一个 javascript 方法,它会删除所有事件侦听器。这是从 dispose 函数中调用的,如下所示:

public ValueTask DisposeAsync()
{
    ViewModel.PropertyChanged -= OnPropertyChangedHandler;
    GC.SuppressFinalize(this);
    return JSRuntime.InvokeVoidAsync("deInitializeDropZone");
}

这是可行的,但是如果我在浏览器中重新加载页面(F5 或重新加载按钮),则会出现以下异常:

fail: Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HMI59N5RRGP7", Request id "0HMI59N5RRGP7:0000000E": An unhandled exception was thrown by the application.
      System.InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method.
         at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(Int64 asyncHandle, String identifier, String argsJson, JSCallResultType resultType, Int64 targetInstanceId)
         at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, CancellationToken cancellationToken, Object[] args)
         at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
         at Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(IJSRuntime jsRuntime, String identifier, Object[] args)
         at Microsoft.AspNetCore.Components.RenderTree.Renderer.<>c__DisplayClass69_0.<<Dispose>g__HandleAsyncExceptions|1>d.MoveNext()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.HandleException(Exception exception)
         at Microsoft.AspNetCore.Components.RenderTree.Renderer.<>c__DisplayClass69_0.<Dispose>g__NotifyExceptions|2(List`1 exceptions)
         at Microsoft.AspNetCore.Components.RenderTree.Renderer.<>c__DisplayClass69_0.<<Dispose>g__HandleAsyncExceptions|1>d.MoveNext()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Components.RenderTree.Renderer.DisposeAsync()
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.<DisposeAsync>g__Await|22_0(Int32 i, ValueTask vt, List`1 toDispose)
         at Microsoft.AspNetCore.Http.Features.RequestServicesFeature.<DisposeAsync>g__Awaited|9_0(RequestServicesFeature servicesFeature, ValueTask vt)
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<FireOnCompleted>g__ProcessEvents|227_0(HttpProtocol protocol, Stack`1 events)
warn: Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer[100]
      Unhandled exception rendering component: JavaScript interop calls cannot be issued at this time. This is because the circuit has disconnected and is being disposed.
      Microsoft.JSInterop.JSDisconnectedException: JavaScript interop calls cannot be issued at this time. This is because the circuit has disconnected and is being disposed.
         at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(Int64 asyncHandle, String identifier, String argsJson, JSCallResultType resultType, Int64 targetInstanceId)
         at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, CancellationToken cancellationToken, Object[] args)
         at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
         at Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(IJSRuntime jsRuntime, String identifier, Object[] args)
         at Microsoft.AspNetCore.Components.RenderTree.Renderer.<>c__DisplayClass69_0.<<Dispose>g__HandleAsyncExceptions|1>d.MoveNext()
fail: Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost[111]
      Unhandled exception in circuit 'blLlOrw1UtfEHUoPBbO_N3peh7u3Or5Uk51p5RbR5xA'.
      Microsoft.JSInterop.JSDisconnectedException: JavaScript interop calls cannot be issued at this time. This is because the circuit has disconnected and is being disposed.
         at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(Int64 asyncHandle, String identifier, String argsJson, JSCallResultType resultType, Int64 targetInstanceId)
         at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, CancellationToken cancellationToken, Object[] args)
         at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
         at Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(IJSRuntime jsRuntime, String identifier, Object[] args)
         at Microsoft.AspNetCore.Components.RenderTree.Renderer.<>c__DisplayClass69_0.<<Dispose>g__HandleAsyncExceptions|1>d.MoveNext()

这只会在重新加载时发生,如果我切换到另一个页面,也会调用 dispose 函数,但也不例外。 我不完全确定这个问题的原因是什么。也许它也可能与初始化有关,这发生在第一次渲染之后:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        var authState = await AuthenticationStateTask;
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            if (await ViewModel.LoadSelectedDatabase(DatasetID))
            {
                await JSRuntime.InvokeVoidAsync("initializeDropZone");
            }
            else
            {
                await JSRuntime.InvokeVoidAsync("alert", "The selected Dataset does not exist!");
                NavigationManager.NavigateTo($"datasets");
            }
        }
    }

    await base.OnAfterRenderAsync(firstRender);

    return;
}

Edit:更多测试,在之前抛出异常await JSRuntime.InvokeVoidAsync("initializeDropZone");重新加载后调用。

Edit#2:我还切换了JS功能:

public ValueTask DisposeAsync()
{
    ViewModel.PropertyChanged -= OnPropertyChangedHandler;
    GC.SuppressFinalize(this);

    return JSRuntime.InvokeVoidAsync("console.log", "testilein");
    //return JSRuntime.InvokeVoidAsync("deInitializeDropZone");
}

这将导致重新加载时出现相同的错误。


由于当 SignalR 连接断开时不可能调用 JavaScript,因此我认为推荐的方法是将其包装在 try-catch 中并捕获JSDisconnectedException如下所示。 由于事件侦听器页面重新加载后停止存在没有内存泄漏。 话虽如此,我同意这不是很“优雅”......

async ValueTask IAsyncDisposable.DisposeAsync()
{
    try
    {
        ViewModel.PropertyChanged -= OnPropertyChangedHandler;
        GC.SuppressFinalize(this);
        await JSRuntime.InvokeVoidAsync("deInitializeDropZone"); 
    }
    catch (JSDisconnectedException ex)
    {
         // Ignore
    }
}

旁注我明确了实现,因为它只能在接口的实例上访问。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Blazor 服务器端应用程序在重新加载期间抛出“System.InvalidOperationException:此时无法发出 JavaScript 互操作调用。...” 的相关文章

随机推荐