将SignalR 2.0 .NET客户端重新连接到服务器集线器的最佳实践

我在移动应用程序中使用SignalR 2.0与.NET客户端,所以我需要处理各种types的断开连接。 有时SignalR客户端在没有我的帮助的情况下重新连接 – 有时我必须通过再次调用HubConnection.Start()来重新连接。 (因为SignalR神奇地自动重新连接一些时间,我想知道如果我错过了function或configuration设置)

build立一个自动重新连接的客户端的最佳方法是什么? 我已经看到处理闭合()事件,然后连接n秒后的JavaScript示例。 有没有推荐的方法?

我已经阅读了关于SignalR连接生命周期的文档和一些文章,但是我仍然不清楚如何处理客户端重新连接。

谢谢!

我终于明白了这一点。 这是自从开始这个问题以来我学到的东西:

背景:我们正在使用Xamarin / Monotouch和.NET SignalR 2.0.3客户端构buildiOS应用程序。 我们正在使用默认的SignalR协议 – 它似乎是使用SSE而不是Web套接字。 我不确定是否可以在Xamarin / Monotouch中使用Web套接字。 一切都使用Azure网站托pipe。

我们需要应用程序快速重新连接到我们的SignalR服务器,但是我们在连接没有自己重新连接的时候一直存在问题 – 或者重新连接需要30秒(由于基础协议超时)。

我们最终testing了三种情况:

schemeA – 首次加载应用程序时连接。 这从一开始就完美无缺。 即使通过3G移动连接,连接也不到0.25秒。 (假设收音机已经打开)

schemeB – 在应用程序闲置/closures30秒后重新连接到SignalR服务器。 在这种情况下,SignalR客户端最终将自己重新连接到服务器上,而不需要任何特殊的工作 – 但是在尝试重新连接之前似乎要等待30秒。 (对于我们的应用程序太慢了)

在这30秒钟的等待期间,我们尝试调用无效的HubConnection.Start()。 并调用HubConnection.Stop()也需要30秒。 我在SignalR网站上发现了一个似乎已经解决的相关bug ,但是我们仍然在v2.0.3中遇到同样的问题。

schemeC – 在应用程序闲置/closures120秒或更长时间后,重新连接到SignalR服务器。 在这种情况下,SignalR传输协议已经超时,所以客户端永远不会自动重新连接。 这就解释了为什么客户有时候并不总是自己重新连接。 好消息是,调用HubConnection.Start()几乎就像场景A一样工作。

所以我花了一段时间才意识到,重新连接的条件是不同的,根据应用程序是否closures了30秒比120+秒。 尽pipeSignalR跟踪日志能够说明底层协议发生了什么,但我不认为有办法在代码中处理传输级事件。 (Closed()事件在场景B中的30秒之后触发,即时在场景C中;状态属性在这些重新连接等待期间表示“已连接”;没有其他相关的事件或方法)

解决scheme:解决scheme很明显。 我们不等待SignalR做重新连接的魔法。 相反,当应用程序被激活或手机的networking连接恢复时,我们只是简单地清理事件并取消引用HubConnection(不能处理它,因为它需要30秒,希望垃圾回收会照顾它)并创build一个新的实例。 现在一切都很好。 出于某种原因,我认为我们应该重用持久连接并重新连接,而不是仅仅创build一个新的实例。

在断开的事件上设置一个定时器来自动尝试重新连接是我知道的唯一方法。

在JavaScript中,它是这样做的:

$.connection.hub.disconnected(function() { setTimeout(function() { $.connection.hub.start(); }, 5000); // Restart connection after 5 seconds. }); 

这是文档中推荐的方法:

http://www.asp.net/signalr/overview/signalr-20/hubs-api/handling-connection-lifetime-events#clientdisconnect

由于OP要求.NET客户端 (下面的Winform实现),

 private async Task<bool> ConnectToSignalRServer() { bool connected = false; try { Connection = new HubConnection("server url"); Hub = Connection.CreateHubProxy("MyHub"); await Connection.Start(); //See @Oran Dennison's comment on @KingOfHypocrites's answer if (Connection.State == ConnectionState.Connected) { connected = true; Connection.Closed += Connection_Closed; } return connected; } catch (Exception ex) { Console.WriteLine("Error"); return false; } } private async void Connection_Closed() { if(!IsFormClosed) // A global variable being set in "Form_closing" event of Form, check if form not closed explicitly to prevent a possible deadlock. { // specify a retry duration TimeSpan retryDuration = TimeSpan.FromSeconds(30); while (DateTime.UtcNow < DateTime.UtcNow.Add(retryDuration)) { bool connected = await ConnectToSignalRServer(UserId); if (connected) return; } Console.WriteLine("Connection closed") } } 

在重新连接状态开始之前,您可能会尝试从您的android调用服务器方法,以防止魔法重新连接问题。

SignalR Hub C#

  public class MyHub : Hub { public void Ping() { //ping for android long polling } } 

在Android中

 private final int PING_INTERVAL = 10 * 1000; private boolean isConnected = false; private HubConnection connection; private ClientTransport transport; private HubProxy hubProxy; private Handler handler = new Handler(); private Runnable ping = new Runnable() { @Override public void run() { if (isConnected) { hubProxy.invoke("ping"); handler.postDelayed(ping, PING_INTERVAL); } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); System.setProperty("http.keepAlive", "false"); ..... ..... connection.connected(new Runnable() { @Override public void run() { System.out.println("Connected"); handler.postDelayed(ping, PING_INTERVAL); }); }