我在 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");
}
这将导致重新加载时出现相同的错误。