【问题标题】:SignalR in ASP.NET Core 3.0 MVC connection keep alive not working?ASP.NET Core 3.0 MVC 连接中的 SignalR 保持活动状态不起作用?
【发布时间】:2020-03-04 12:23:59
【问题描述】:

一句话的问题:SignalR连接是否通过keep-alives保持打开状态,如果是,为什么它们不能在.NET Core 3中工作,如果不是,keep-alive设置有什么用?

我有一个 ASP.NET Core 3.0 MVC Web 应用程序,我刚刚按照位于此处的入门教程将 SignalR 添加到它:https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr?view=aspnetcore-3.0&tabs=visual-studio(减去创建一个新的 Web 应用程序,我们只是将它添加到我们的应用程序)

我有一个简单的集线器,客户端连接成功,如果我在连接建立后立即测试 SignalR 方法,它可以工作。但是,如果我在 30 秒内不使用它,连接就会关闭。如果我理解文档,keepalive 的默认值为 15 秒,但我没有看到任何 keepalive 消息。我尝试了 KeepAliveInterval 和 ClientTimeoutInterval 的各种设置,但都没有解决这个问题。

我在我们的 javascript 中将 .withAutomaticReconnect() 添加到 HubConnectionBuilder 调用中,这确实可以在每 30 秒断开连接后重新建立连接。这是应该如何工作的,还是应该通过 ping 保持连接活动并且只需要由于网络丢失/等而重新连接?我觉得我遗漏了一些简单的东西,或者我误解了它应该如何工作。

以下是我们的代码的各个部分:

Startup.cs ConfigureServices 方法:

        services.AddSignalR(hubOptions =>
        {
            hubOptions.EnableDetailedErrors = true;
            //hubOptions.KeepAliveInterval = TimeSpan.FromSeconds(10);
            //hubOptions.ClientTimeoutInterval = TimeSpan.FromMinutes(1);
        });

Startup.cs 配置方法:

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
            endpoints.MapRazorPages();
            endpoints.MapHub<QuoteHub>("/quoteHub");
        });

我们的报价中心:

public class QuoteHub : Hub
{
    public QuoteHub()
    {

    }

    public override Task OnConnectedAsync()
    {
        var quoteId = Context.GetHttpContext().Request.Query["quoteId"];

        return Groups.AddToGroupAsync(Context.ConnectionId, quoteId);
    }
}

以及连接的 javascript 设置:

const setupQuoteConnection = (quoteId) => {
    let connection = new signalR.HubConnectionBuilder()
    .withUrl("/quoteHub?quoteId=" + quoteId)
    .configureLogging(signalR.LogLevel.Debug)
    .withAutomaticReconnect()
    .build();

    connection.on("ReceiveUpdate", (update) => {
    alert(update);
    }
    );

    connection.start()
    .catch(err => console.error(err.toString()));
};

并且,为了彻底起见,调用中心将更新发送给客户端:

_quoteHub.Clients.Group(domainEvent.QuoteId.ToString()).SendAsync("ReceiveUpdate", domainEvent.TotalPrice);

更新

我在https://github.com/aspnet/SignalR-samples 找到了聊天示例。我下载并运行了该示例,它运行良好,连接保持打开状态,但对于我来说,我看不出是什么导致它的行为与我的应用程序不同。

我确实注意到了我的集线器中的一些问题并修复了它,尽管这并没有什么区别:

public class QuoteHub : Hub
{
    public override async Task OnConnectedAsync()
    {
        var quoteId = Context.GetHttpContext().Request.Query["quoteId"];

        await Groups.AddToGroupAsync(Context.ConnectionId, quoteId);

        await base.OnConnectedAsync();
    }
}

然后我更新了我的 javascript 代码来配置连接并延长服务器超时时间。这确实有效,但是当上面链接的聊天示例没有它并且没有它也能正常工作时,为什么我需要它?

    let connection = new signalR.HubConnectionBuilder()
    .withUrl("/quoteHub?quoteId=" + quoteId)
    .configureLogging(signalR.LogLevel.Debug)
    .withAutomaticReconnect()
    .build();

    connection.serverTimeoutInMilliseconds = 3600000; //1 hour

【问题讨论】:

    标签: javascript c# typescript asp.net-core signalr


    【解决方案1】:

    看来我们已经确定了导致我们持续 30 秒断线的罪魁祸首。

    当我们将应用程序从 ASP.NET Core 2.2 MVC 更新到 3.0 时,我们也完全采用了 System.Text.Json 迁移(远离 Newtonsoft.Json)。好吧,这有一个副作用,就是破坏了仍然需要 Newtonsoft.Json 的 Telerik Reporting 组件。因此,我们在我们的应用程序中恢复使用 Newtonsoft.Json,但我们丢失的部分在 https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=visual-studio#switch-to-newtonsoftjson

    关键位是“将 AddNewtonsoftJsonProtocol 方法调用链接到 Startup.ConfigureServices 中的 AddSignalR 方法调用”:

    services.AddSignalR()
    .AddNewtonsoftJsonProtocol
    

    这一切都不需要其他任何东西来“正常工作”。如果您正在阅读本文,请参考我在问题更新中提到的聊天示例 (https://github.com/aspnet/SignalR-samples)。该代码的简单性及其运行方式向我表明,我们看到不断断开连接的方式有问题 - 让我措手不及的红鲱鱼是我们的 SignalR 消息仍然有效。

    【讨论】:

      【解决方案2】:

      我想你可能还需要添加 options.Transports 这样的

      public void ConfigureServices(IServiceCollection services)
      {
          services.AddSignalR(hubOptions =>
          {
              hubOptions.EnableDetailedErrors = true;
              hubOptions.KeepAliveInterval = TimeSpan.FromMinutes(1);
          });
      }
      
      public void Configure(IApplicationBuilder app, IHostingEnvironment env)
      {
          app.UseRouting();
      
          app.UseEndpoints(endpoints =>
          {
              endpoints.MapHub<MyHub>("/myhub", options =>
              {
                  options.Transports = HttpTransportType.LongPolling; // you may also need this
              });
          });
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-03
        • 2021-09-13
        相关资源
        最近更新 更多