ASP.NET Core 3.0 MVC 连接中的 SignalR 保持活动状态不工作?
SignalR in ASP.NET Core 3.0 MVC connection keep alive not working?
一句话中的问题: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 保持连接,并且只需要由于网络 dropouts/etc 重新连接?我觉得我遗漏了一些简单的东西,或者我误解了它应该如何工作。
以下是我们代码的各个部分:
Startup.cs 配置服务方法:
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
我想你可能还需要像这样添加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
});
});
}
看来我们已经确定了持续 30 秒断开连接的罪魁祸首。
当我们将应用程序从 ASP.NET Core 2.2 MVC 更新到 3.0 时,我们也进行了 System.Text.Json 的迁移(远离 Newtonsoft.Json)。嗯,这有破坏我们的 Telerik 报告组件的副作用,它仍然需要 Newtonsoft.Json。因此,我们在我们的应用程序中恢复使用 Newtonsoft.Json,但我们丢失的部分在 https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=visual-studio#switch-to-newtonsoftjson
处找到
关键位是"chain an AddNewtonsoftJsonProtocol method call to the AddSignalR method call in Startup.ConfigureServices":
services.AddSignalR()
.AddNewtonsoftJsonProtocol
'just work' 不需要其他任何东西。如果您正在阅读本文,请参考我在问题更新中提到的聊天示例 (https://github.com/aspnet/SignalR-samples)。该代码的简单性及其 运行 对我来说是一个信号,表明我们看到不断断开连接的方式有些不对劲 - 让我措手不及的是我们的 SignalR 消息仍然有效。
一句话中的问题: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 保持连接,并且只需要由于网络 dropouts/etc 重新连接?我觉得我遗漏了一些简单的东西,或者我误解了它应该如何工作。
以下是我们代码的各个部分:
Startup.cs 配置服务方法:
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
我想你可能还需要像这样添加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
});
});
}
看来我们已经确定了持续 30 秒断开连接的罪魁祸首。
当我们将应用程序从 ASP.NET Core 2.2 MVC 更新到 3.0 时,我们也进行了 System.Text.Json 的迁移(远离 Newtonsoft.Json)。嗯,这有破坏我们的 Telerik 报告组件的副作用,它仍然需要 Newtonsoft.Json。因此,我们在我们的应用程序中恢复使用 Newtonsoft.Json,但我们丢失的部分在 https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=visual-studio#switch-to-newtonsoftjson
处找到关键位是"chain an AddNewtonsoftJsonProtocol method call to the AddSignalR method call in Startup.ConfigureServices":
services.AddSignalR()
.AddNewtonsoftJsonProtocol
'just work' 不需要其他任何东西。如果您正在阅读本文,请参考我在问题更新中提到的聊天示例 (https://github.com/aspnet/SignalR-samples)。该代码的简单性及其 运行 对我来说是一个信号,表明我们看到不断断开连接的方式有些不对劲 - 让我措手不及的是我们的 SignalR 消息仍然有效。