Blazor Server应用触发WebSocket 1006错误冻结,求根因排查与修复
Blazor Server应用WebSocket 1006错误排查与修复
问题说明
Blazor Server端应用执行特定代码时出现屏幕冻结,Chrome和Firefox浏览器均触发错误:WebSocket closed with status code: 1006 (no reason given)。具体场景:
- 页面首次打开后,第一次调用
ReadVariables方法(once=true):执行AGL4.NCK_Symbolic_LoadGUD和AGL4.NCK_Symbolic_GetNCKDataRWByBTSSItem,输出正常。 - 第二次调用该方法(
once=false):仅执行AGL4.NCK_Symbolic_GetNCKDataRWByBTSSItem,使用首次保存的root_handle_2,在标记abc的代码行触发屏幕冻结,服务端无任何报错。
相关代码
public AGL4.NckNodeHandle root_handle_2 ; public bool once = true; public void ReadVariables(int p_conn_nr) { int res = AGL4.AGL40_SUCCESS; if (once == true) { AGL4.NckNodeHandle root_handle = new AGL4.NckNodeHandle(); res = AGL4.NCK_Symbolic_LoadGUD(p_conn_nr, ref root_handle); root_handle_2 = root_handle; once = false; } int variables_count = TagService.GUD_VAR_names.Count; //准备待读取的变量列表 AGL4.NckDataRW[] data_rws = new AGL4.NckDataRW[variables_count]; using (StreamWriter sw = File.AppendText(error_path)) for (int i = 0; i < variables_count; ++i) { data_rws[i] = new AGL4.NckDataRW(); string variable = TagService.GUD_VAR_names[i]; int error_position = 0; // abc: 第二次执行时此处触发冻结与WebSocket错误 res = AGL4.NCK_Symbolic_GetNCKDataRWByBTSSItem(root_handle_2, variable, ref data_rws[i], ref error_position); } }
排查方向
- AGL4库线程安全性检查:Blazor Server组件方法默认在UI线程执行,若AGL4的非托管函数不是线程安全的,重复调用可能引发死锁或资源冲突。
- root_handle_2有效性验证:第二次调用时,
root_handle_2是否已被AGL4库自动释放或失效?需确认NCK_Symbolic_LoadGUD返回的句柄生命周期规则,是否存在超时回收机制。 - 同步阻塞问题排查:如果
NCK_Symbolic_GetNCKDataRWByBTSSItem是同步阻塞调用且耗时过长,会卡住Blazor的SignalR UI线程,触发WebSocket断开(Blazor Server对UI线程阻塞有超时限制)。 - 添加详细日志:在
GetNCKDataRWByBTSSItem调用前后记录日志,包括当前变量名、句柄状态(若可获取),定位是否在处理某个特定变量时卡住。 - 资源泄漏检查:第一次调用创建的资源是否未正确释放,导致第二次调用时资源不足或句柄异常。
修复建议
- 异步化调用避免UI阻塞
将ReadVariables改为异步方法,把AGL4的调用放到后台线程执行,防止阻塞UI线程引发WebSocket断开:
public async Task ReadVariables(int p_conn_nr) { int res = AGL4.AGL40_SUCCESS; if (once == true) { await Task.Run(() => { AGL4.NckNodeHandle root_handle = new AGL4.NckNodeHandle(); res = AGL4.NCK_Symbolic_LoadGUD(p_conn_nr, ref root_handle); root_handle_2 = root_handle; once = false; }); } int variables_count = TagService.GUD_VAR_names.Count; AGL4.NckDataRW[] data_rws = new AGL4.NckDataRW[variables_count]; await Task.Run(() => { for (int i = 0; i < variables_count; ++i) { data_rws[i] = new AGL4.NckDataRW(); string variable = TagService.GUD_VAR_names[i]; int error_position = 0; res = AGL4.NCK_Symbolic_GetNCKDataRWByBTSSItem(root_handle_2, variable, ref data_rws[i], ref error_position); // 添加错误检查,避免循环卡住 if (res != AGL4.AGL40_SUCCESS) { // 记录错误并中断循环 break; } } }); // 若需更新UI,通过InvokeAsync切换回UI线程 await InvokeAsync(() => { // 更新UI逻辑 }); }
句柄有效性校验
在第二次调用GetNCKDataRWByBTSSItem前,使用AGL4库提供的句柄验证函数(若存在)检查root_handle_2是否有效,若无效则重新执行NCK_Symbolic_LoadGUD加载句柄。添加错误处理与日志
在循环中检查res返回值,记录每次调用的错误信息,快速定位异常变量或调用失败原因。确保线程安全
若AGL4库不是线程安全的,需使用lock同步所有AGL4函数调用,或确保所有调用在同一个线程上下文执行。
内容的提问来源于stack exchange,提问作者Mdarende
相关产品推荐
相关产品推荐

