Blazor 服务器:修复“无法重新连接到服务器”问题

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

我在 .NET 8 Blazor Server 中开发了一个应用程序(使用 SignalR 服务部署到 Azure)。用户经常开始在表单中输入一些信息(通常是相当多的信息),然后被拉到其他问题上,然后回来发现服务器已断开连接;屏幕呈灰色,屏幕顶部的消息为:“无法重新连接到服务器。重新加载页面以恢复功能”。断开连接所需的时间似乎是随机的。

客户端希望连接在上次 UI 活动后至少 2 小时内保持活动状态。我试过了:

  • Chrome、设置、性能、内存节省程序:关闭
  • Chrome、设置、性能:将网站添加到“始终保持这些网站处于活动状态”
  • Program.cs:builder.Services.AddServerSideBlazor:设置 DisconnectedCircuitRetentionPeriod
  • _Layout.cshtml:添加包含“builder.withServerTimeout(7200000)”的JS脚本

有办法解决这个问题吗?或者,我们是否使用了错误的技术进行开发?

提前致谢。

server blazor timeout asp.net-core-signalr disconnect
1个回答
0
投票

以下代码可以解决下面截图中的

Could not reconnect to the server. Reload the page to restore functionality.
问题。我初步算了一下,大概需要10秒才能自动恢复。

enter image description here

这是我的测试代码

_主机.cshtml

@page "/"
@using Microsoft.AspNetCore.Components.Web
@namespace BlazorApp2.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
    <link href="BlazorApp2.styles.css" rel="stylesheet" />
    <link rel="icon" type="image/png" href="favicon.png"/>
    <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
    <component type="typeof(App)" render-mode="ServerPrerendered" />

    <div id="blazor-error-ui">
        <environment include="Staging,Production">
            An error has occurred. This application may no longer respond until reloaded.
        </environment>
        <environment include="Development">
            An unhandled exception has occurred. See browser dev tools for details.
        </environment>
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    @*  autostart="false" here *@
    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.0/signalr.min.js"></script>
    <script>
        // connect heartbeatHub
        const connection = new signalR.HubConnectionBuilder()
            .withUrl("/heartbeatHub")
            .build();

        connection.start().then(() => {
            console.log("Connected to heartbeatHub");

            setInterval(() => {
                connection.invoke("SendHeartbeat")
                    .then(() => console.log("Heartbeat sent"))
                    .catch(err => console.error(err.toString()));
            }, 5 * 60 * 1000); // Every 5 minutes will sent a Heartbeat
        }).catch(err => console.error(err.toString()));

        connection.on("HeartbeatReceived", (message) => {
            console.log(`Server response: ${message}`);
        });
        connection.onclose(async () => {
            console.log("Connection closed, retrying...");
            await connection.start();
        });
        // For reconnecting the _blazor default hub
        Blazor.start().then(() => {
            Object.defineProperty(Blazor.defaultReconnectionHandler, '_reconnectionDisplay', {
                get() {
                    return this.__reconnectionDisplay;
                },
                set(value) {
                    this.__reconnectionDisplay = {
                        show: () => value.show(),
                        update: (d) => value.update(d),
                        rejected: (d) => document.location.reload()
                    }
                }
            });
        });
    </script>
</body>
</html>

HeartbeatHub.cs

using Microsoft.AspNetCore.SignalR;

namespace BlazorApp2
{
    public class HeartbeatHub : Hub
    {
        public async Task SendHeartbeat()
        {
            Console.WriteLine($"Received heartbeat from {Context.ConnectionId} at {DateTime.UtcNow}");

            await Clients.Caller.SendAsync("HeartbeatReceived", "pong");
        }
    }
}

程序.cs

using BlazorApp2;
using BlazorApp2.Data;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
// [Optional] The second steps to check the size of your data in the form
builder.Services.AddServerSideBlazor().AddHubOptions(options =>
{
    options.MaximumReceiveMessageSize = 1024 * 1024; // Set Size = 1MB
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();
// Register HeartbeatHub
app.MapHub<HeartbeatHub>("/heartbeatHub");

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();
© www.soinside.com 2019 - 2024. All rights reserved.