Blazor 服务器“错误:服务器超时,但未收到来自服务器的消息。”即使发送我自己的保持活动消息

问题描述 投票:0回答:1

我几个月来一直在尝试解决 Balzor 服务器应用程序中的服务器超时断开连接问题。 我尝试了很多不同的方法,但到目前为止没有任何效果。 我刚刚完成应用程序,但无法修复这些断开连接。

客户端应用程序认为它尚未收到来自服务器的消息,并且每隔 30 秒左右就会出现一次“尝试重新连接到服务器:1 of 8”开始。 它每次都会成功重新连接,但我需要这些重新连接消息来停止。

这是我尝试失败的 SignalR 配置示例。

 
     Blazor.start({
         reconnectionOptions: {
             maxRetries: 100,
             retryIntervalMilliseconds: 2000
         },
         configureSignalR: function (builder) {
             let c = builder.build();
             c.serverTimeoutInMilliseconds = 30000;
             c.keepAliveIntervalInMilliseconds = 10000;
             builder.build = () => {
                 return c;
             };
         }
     });
 

通过调整此代码中的持续时间,我可以更改断开连接的频率,但它们仍然会发生。

我决定向客户端发送我自己的“FakeKeepAlive”消息。

    private async Task StartFakeKeepAlive(CancellationToken ct)
    {
        try
        {
            using (var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(Utils.GlobalKeepAliveIntervalInMilliseconds)))
            {
                while (!ct.IsCancellationRequested)
                {
                    await timer.WaitForNextTickAsync(ct);

                    now = DateTime.Now;
                    Debug.WriteLine($"FakeKeepAlive {now.ToString("h:mm:ss.FFF")} ");
                    await JS.InvokeVoidAsync("console.log", "CSDKeepAlive: At ", DateTime.Now.ToString("h:mm:ss.FFF"));
                    await InvokeAsync(StateHasChanged);
                }
            }
        }
        catch (Exception ex)
        {
            logger.Warn(ex, "StartFakeKeepAlive() exception");
            throw;
        }

    }

请注意,我尝试了 InvokeAsync(StateHasChanged) 和 JS Interop 来向客户端发送 console.log 消息以及这两者。

这有助于延迟断开连接的开始,但大约 5 分钟后断开连接再次出现。

这是 Chrome 控制台输出:

[2024-04-15T20:21:24.628Z] Information: Normalizing '_blazor' to 'https://localhost:5001/_blazor'. blazor.server.js:1 

[2024-04-15T20:21:24.673Z] Information: WebSocket connected to wss://localhost:5001/_blazor?id=fulG9OiaSbyn6AO1yCwIwQ. blazor.server.js:1 

CSDKeepAlive: At  4:22:01.339 blazor.server.js:1 

CSDKeepAlive: At  4:22:31.333 blazor.server.js:1 

CSDKeepAlive: At  4:23:01.331 blazor.server.js:1 

CSDKeepAlive: At  4:23:31.326 blazor.server.js:1 

CSDKeepAlive: At  4:24:01.331 blazor.server.js:1 

CSDKeepAlive: At  4:24:31.328 blazor.server.js:1 

CSDKeepAlive: At  4:25:01.331 blazor.server.js:1 

CSDKeepAlive: At  4:25:31.327 blazor.server.js:1 

CSDKeepAlive: At  4:26:01.329 blazor.server.js:1 

CSDKeepAlive: At  4:26:31.327 blazor.server.js:1 

CSDKeepAlive: At  4:27:01.329 blazor.server.js:1 

CSDKeepAlive: At  4:27:31.339 blazor.server.js:1 

CSDKeepAlive: At  4:28:01.327 blazor.server.js:1 

[2024-04-15T20:28:31.332Z] Error: Connection disconnected with error 'Error: Server timeout elapsed without receiving a message from the server.'. 

  log @ blazor.server.js:1

  _stopConnection @ blazor.server.js:1

  features.reconnect.transport.onclose @ blazor.server.js:1

  _close @ blazor.server.js:1

  stop @ blazor.server.js:1

  _stopInternal @ blazor.server.js:1

  await in _stopInternal (async)

  stop @ blazor.server.js:1

  serverTimeout @ blazor.server.js:1

  (anonymous) @ blazor.server.js:1

  setTimeout (async) _resetTimeoutPeriod @ blazor.server.js:1

  _processIncomingData @ blazor.server.js:1

  Xt.connection.onreceive @ blazor.server.js:1

  s.onmessage @ blazor.server.js:1

  blazor.server.js:1

[2024-04-15T20:28:34.341Z] Information: Normalizing '_blazor' to 'https://localhost:5001/_blazor'. blazor.server.js:1 

[2024-04-15T20:28:34.354Z] Information: WebSocket connected to wss://localhost:5001/_blazor?id=VbjkvE9CAzGk89_vdVcqng. blazor.server.js:1 

[2024-04-15T20:29:07.836Z] Error: Connection disconnected with error 'Error: Server timeout elapsed without receiving a message from the server.'. 

  {Details omitted, but same as above}

[2024-04-15T20:29:10.843Z] Information: Normalizing '_blazor' to 'https://localhost:5001/_blazor'. blazor.server.js:1 

[2024-04-15T20:29:10.850Z] Information: WebSocket connected to wss://localhost:5001/_blazor?id=5MLFdZ6qPPwEdrn5djWidg.

这是program.cs中的相关代码。 请注意,注释掉的代码是尝试在此处设置保持活动间隔。 上面的示例使用默认的 ServerTimeout 和 KeepAliveIntervals。


    //builder.Services.AddServerSideBlazor().AddHubOptions(option =>
    //    {
    //        option.KeepAliveInterval = TimeSpan.FromMilliseconds(Utils.GlobalKeepAliveIntervalInMilliseconds);
    //    });
    builder.Services.AddServerSideBlazor().AddCircuitOptions(option =>
        {
            option.DetailedErrors = true;
        });

这是我的 .csproj 文件中的整个包部分。

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.3" />
    <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.3" />
    <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.3">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="MudBlazor" Version="6.15.0" />
    <PackageReference Include="NLog" Version="5.2.8" />
    <PackageReference Include="NLog.Web.AspNetCore" Version="5.3.8" />
    <PackageReference Include="Radzen.Blazor" Version="4.24.5" />
    <PackageReference Include="Versus_NAPI_Core" Version="4.0.0-20230918.7" />
  </ItemGroup>enter image description here

这是其余的依赖项:

其他 Visual Studio 依赖项的屏幕截图

我几周来一直在努力解决这个问题。我相信我已经阅读了所有可能与此内容以及所有 Microsoft 文档有关的 Stack Overflow 帖子。 我的经历与我读过的所有内容都不一致,所以我想知道我是否遗漏了更深层的东西。

我无法辨别为什么断开连接仅在 5 分钟后才开始,以及为什么我的“FakeKeepAlive”消息在连接重置后没有收到。

无论如何,我在 .NET 7.0 中启动了该应用程序,但升级到了 .NET 8.0。 这个问题在我升级之前就出现了。

asp.net blazor blazor-server-side signalr.client asp.net-core-signalr
1个回答
0
投票

升级至 Microsoft 支持后,发现问题出在我们系统使用的 dll 库,该库最初是作为 WinForms 控件实现的。

Per Microsoft...“似乎构建 WinForms 控件会在当前线程上设置 WindowsFormsSynchronizationContext。与 ASP.NET Core 框架的其余部分不同,SignalR 不会使用 ConfigureAwait(false) 等待任务,因为它期望 SynchronizationContext null 在 ASP.NET Core 应用程序中,但是,像 .NET SignalR 客户端这样的客户端库(可以在 ASP.NET Core 应用程序之外使用)是此规则的例外。

在您的应用程序中,当 SignalR 在启动期间初始化其保持活动循环时,SynchronizationContext 为非空,导致其卡住并无法发送保持活动。”

他们建议将 SynchronizationContext.SetSynchronizationContext(null) 放入 dll 的初始化中,但警告说这会破坏 WinForm 功能。

我通过创建删除所有 WinForms 引用的库版本解决了该问题。

© www.soinside.com 2019 - 2024. All rights reserved.