You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor Server(.NET8)重载页面触发NullReferenceException求助

解决Blazor Server(.NET 8)页面重载后的NullReferenceException问题

问题场景

我正在排查Blazor Server(.NET 8)应用的页面重载异常问题:应用头部有一个国家选择下拉框,切换选项后需要重载整个页面。尝试调用NavigationManager.NavigateTo(NavigationManager.Uri, true, true)实现重载,页面确实刷新了,但随后抛出NullReferenceException,且异常未指向业务代码。用await JavaScriptRuntime.InvokeVoidAsync("location.reload")替代也会出现同样异常,但手动刷新页面(地址栏回车)时一切正常。在Visual Studio模板新项目中无法复现该问题,即使引入了实际项目的ProtectedLocalStorage也正常。

异常详情

System.NullReferenceException: Object reference not set to an instance of an object.

调用栈:

Microsoft.AspNetCore.Components.Server.dll!Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.EndInvokeDotNet(Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo, Microsoft.JSInterop.Infrastructure.DotNetInvocationResult invocationResult) Line 201 C#
Microsoft.JSInterop.dll!Microsoft.JSInterop.Infrastructure.DotNetDispatcher.EndInvokeDotNetAfterTask(System.Threading.Tasks.Task task, Microsoft.JSInterop.JSRuntime jsRuntime, Microsoft.JSInterop.Infrastructure.DotNetInvocationInfo invocationInfo) Line 164 C#
Microsoft.JSInterop.dll!Microsoft.JSInterop.Infrastructure.DotNetDispatcher.BeginInvokeDotNet.AnonymousMethod__0(System.Threading.Tasks.Task t) Line 124 C#
System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread threadPoolThread, System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Line 264 C#
System.Private.CoreLib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot, System.Threading.Thread threadPoolThread) Line 2349 C#
System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() Line 913 C#
System.Private.CoreLib.dll!System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart() Line 102 C#

问题分析

从调用栈可以看出,异常发生在RemoteJSRuntime.EndInvokeDotNet方法的else分支中,推测是_clientProxy实例为空导致。手动刷新正常但代码触发重载异常,说明代码触发的重载过程中,存在未完成的JS互操作调用,在页面刷新后这些调用的回调无法找到有效的电路(Circuit)实例,从而引发空引用。

排查与解决步骤

1. 捕获更详细的异常信息

  • 启用详细日志:在appsettings.json中添加日志配置,记录Microsoft.AspNetCore.Components.Server和Microsoft.JSInterop的Debug级日志,查看是否有未完成的JS调用记录:
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.AspNetCore.Components.Server": "Debug",
      "Microsoft.JSInterop": "Debug"
    }
  }
}
  • 全局异常捕获:在_Host.cshtml中使用ErrorBoundary组件包裹内容,尝试捕获更具体的异常上下文:
<ErrorBoundary>
    <ChildContent>
        @Body
    </ChildContent>
    <ErrorContent>
        <p>未处理异常:@context.Message</p>
        <p>栈跟踪:@context.StackTrace</p>
    </ErrorContent>
</ErrorBoundary>

2. 重载前终止未完成的JS互操作

在调用页面重载前,释放所有JS模块引用并确保异步操作完成:

private IJSObjectReference? _jsModule;

private async Task OnCountryChanged(string countryCode)
{
    // 保存国家设置逻辑...
    
    // 释放JS模块引用
    if (_jsModule != null)
    {
        await _jsModule.DisposeAsync();
        _jsModule = null;
    }
    
    // 短暂延迟确保所有异步操作收尾
    await Task.Delay(100);
    NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
}

3. 跟踪组件生命周期,取消无效回调

在组件中使用CancellationToken跟踪生命周期,销毁时取消所有异步操作,避免组件卸载后触发JS调用:

private CancellationTokenSource _cts = new();

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        _cts.Cancel();
        _cts.Dispose();
    }
    base.Dispose(disposing);
}

private async Task SomeAsyncOperation()
{
    try
    {
        await JSRuntime.InvokeVoidAsync("someJsFunction", _cts.Token);
    }
    catch (OperationCanceledException)
    {
        // 忽略组件销毁时的取消操作
    }
}

4. 替代重载方案

如果上述方法无效,尝试通过表单提交触发页面重载,避免JS互操作残留问题:

<form @ref="formRef" method="get" action="@NavigationManager.Uri">
    <select @onchange="OnCountryChanged">
        <!-- 国家选项 -->
    </select>
</form>

对应的处理逻辑:

private ElementReference formRef;

private async Task OnCountryChanged(ChangeEventArgs e)
{
    // 保存国家设置逻辑...
    await formRef.SubmitAsync();
}

内容的提问来源于stack exchange,提问作者gis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 21:56:08