title: .Net Core SignalR - connection timeout - heartbeat timer - connection state change handling
body: <p>just to be clear up-front, this questions is about .Net Core SignalR, not the previous version.</p>
  
  <p>The new SignalR has an issue with WebSockets behind IIS (I can't get them to work on Chrome/Win7/IIS express). So instead I'm using Server Sent Events (SSE).
  However, the problem is that those time out after about 2 minutes, the connection state goes from 2 to 3. Automatic reconnect has been removed (apparently it wasn't working really well anyway in previous versions).</p>
  
  <p>I'd like to implement a heartbeat timer now to stop clients from timing out, a tick every 30 seconds may well do the job.</p>
  
  <p><strong>Update 10 November</strong></p>
  
  <p>I have now managed to implement the server side Heartbeat, essentially taken from Ricardo Peres' <a href="https://weblogs.asp.net/ricardoperes/signalr-in-asp-net-core" rel="nofollow noreferrer">https://weblogs.asp.net/ricardoperes/signalr-in-asp-net-core</a> </p>
  
  <ul>
  <li>in startup.cs, add to <code>public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)</code></li>
  </ul>
  
  <pre class="lang-cs prettyprint-override"><code>    app.UseSignalR(routes =&gt;  
      {  
          routes.MapHub&lt;TheHubClass&gt;("signalr");  
      });
  
      TimerCallback SignalRHeartBeat = async (x) =&gt; {   
      await serviceProvider.GetService&lt;IHubContext&lt;TheHubClass&gt;&gt;().Clients.All.InvokeAsync("Heartbeat", DateTime.Now); };
      var timer = new Timer(SignalRHeartBeat).Change(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(30));            
  </code></pre>
  
  <ul>
  <li>HubClass</li>
  </ul>
  
  <p>For the HubClass, I have added <code>public async Task HeartBeat(DateTime now) =&gt; await Clients.All.InvokeAsync("Heartbeat", now);</code></p>
  
  <p>Obviously, both the timer, the data being sent (I'm just sending a DateTime) and the client method name can be different.</p>
  
  <h2>Update .Net Core 2.1+</h2>
  
  <p>See the comment below; the timer callback should no longer be used. I've now implemented an IHostedService (or rather the abstract BackgroundService) to do that:</p>
  
  <pre><code>public class HeartBeat : BackgroundService
  {
      private readonly IHubContext&lt;SignalRHub&gt; _hubContext;
      public HeartBeat(IHubContext&lt;SignalRHub&gt; hubContext)
      {
          _hubContext = hubContext;
      }
      protected override async Task ExecuteAsync(CancellationToken stoppingToken)
      {
          while (!stoppingToken.IsCancellationRequested)
          {
              await _hubContext.Clients.All.SendAsync("Heartbeat", DateTime.Now, stoppingToken);
              await Task.Delay(30000, stoppingToken);
          }            
      }
  }
  </code></pre>
  
  <p>In your startup class, wire it in after <code>services.AddSignalR();</code>:</p>
  
  <pre><code>services.AddHostedService&lt;HeartBeat&gt;();
  </code></pre>
  
  <ul>
  <li>Client</li>
  </ul>
  
  <pre class="lang-js prettyprint-override"><code>    var connection = new signalR.HubConnection("/signalr", { transport: signalR.TransportType.ServerSentEvents });
      connection.on("Heartbeat", serverTime =&gt; { console.log(serverTime); });
  </code></pre>
  
  <p><strong>Remaining pieces of the initial question</strong></p>
  
  <p>What is left is how to properly reconnect the client, e.g. after IO was suspended (the browser's computer went to sleep, lost connection, changed Wifis or whatever)</p>
  
  <p>I have implemented a client side Heartbeat that is working properly, at least until the connection breaks:</p>
  
  <ul>
  <li>Hub Class: <code>public async Task HeartBeatTock() =&gt; await Task.CompletedTask;</code></li>
  <li><p>Client: 
  </p>
  
  <p>var heartBeatTockTimer;
  function sendHeartBeatTock() {
     connection.invoke("HeartBeatTock");
  }
  connection.start().then(args => {
     heartBeatTockTimer = setInterval(sendHeartBeatTock, 10000);
  });</p></li>
  </ul>
  
  <p>After the browser suspends IO for example, the invoke method would throw an exception - which cannot be caught by a simple try/catch because it is async.
  What I tried to do for my HeartBeatTock was something like (pseudo-code):</p>
  
  <pre><code>function sendHeartBeatTock
      try connection.invoke("HeartbeatTock)
      catch exception
           try connection.stop()
           catch exception (and ignore it)
           finally
                connection = new HubConnection().start()
      repeat try connection.invoke("HeartbeatTock")
      catch exception
          log("restart did not work")
          clearInterval(heartBeatTockTimer)
          informUserToRefreshBrowser()
  </code></pre>
  
  <p>Now, this does not work for a few reasons. invoke throws the exception after the code block executes due to being run asynchronous. It looks as though it exposes a .catch() method, but I'm not sure how to implement my thoughts there properly.
  The other reason is that starting a new connection would require me to re-implement all server calls like "connection.on("send"...) - which appears silly.</p>
  
  <p>Any hints as to how to properly implement a reconnecting client would be much appreciated.          </p>