Rol*_*ain 13 javascript c# blazor
我在 blazor 应用程序的其中一个页面中实现了一个文件放置区域,该区域是使用 javascript 运行时接口进行处理的。为了避免内存泄漏,我有一个 javascript 方法,它会删除所有事件侦听器。这是从 dispose 函数中调用的,如下所示:
public ValueTask DisposeAsync()
{
ViewModel.PropertyChanged -= OnPropertyChangedHandler;
GC.SuppressFinalize(this);
return JSRuntime.InvokeVoidAsync("deInitializeDropZone");
}
Run Code Online (Sandbox Code Playgroud)
这是可行的,但是如果我在浏览器中重新加载页面(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()
Run Code Online (Sandbox Code Playgroud)
这只会在重新加载时发生,如果我切换到另一个页面,也会调用 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;
}
Run Code Online (Sandbox Code Playgroud)
编辑:更多测试,在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");
}
Run Code Online (Sandbox Code Playgroud)
这将导致重新加载时出现相同的错误。
Jes*_*ood 10
由于当 SignalR 连接断开时不可能调用 JavaScript,因此我认为推荐的方法是将其包装在 try-catch 中并捕获,JSDisconnectedException如下所示。由于事件侦听器在页面重新加载后停止存在,因此不会发生内存泄漏。话虽如此,我同意这不是很“优雅”......
async ValueTask IAsyncDisposable.DisposeAsync()
{
try
{
ViewModel.PropertyChanged -= OnPropertyChangedHandler;
GC.SuppressFinalize(this);
await JSRuntime.InvokeVoidAsync("deInitializeDropZone");
}
catch (JSDisconnectedException ex)
{
// Ignore
}
}
Run Code Online (Sandbox Code Playgroud)
旁注我明确了实现,因为它只能在接口的实例上访问。