Skip to content

Instantly share code, notes, and snippets.

@killnine
Created July 17, 2014 17:52
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save killnine/05c47128735201c32ddc to your computer and use it in GitHub Desktop.
The HubConnectionManager has two responsibilities: first, it exposes a more test-friendly interface by which .NET SignalR clients can connect to a server. The second is to provide a means of retrying connections to the server if `HubConnection.Start()` fails. Once a connection has been established, SignalR is more than capable at retrying connec…
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Client;
/* Requires Microsoft.AspNet.SignalR.Client */
/* Requires Microsoft.Bcl.Async if running on .NET 4.0 */
namespace HubConnectionManager
{
public interface IHubConnectionManager
{
ConnectionState State { get; }
event Action<Exception> Error;
event Action<StateChange> StateChanged;
event Action<string> Received;
event Action Closed;
event Action Reconnecting;
event Action Reconnected;
event Action ConnectionSlow;
Task Initialize(string url);
IHubProxy CreateHubProxy(string hubName);
}
public class HubConnectionManager : IHubConnectionManager
{
private HubConnection _hubConnection;
private readonly Timer _retryTimer;
public ConnectionState State { get { return _hubConnection.State; } }
private int _retryPeriod = 30000;
public int RetryPeriod
{
get { return _retryPeriod; }
set
{
//Sir, you don't want a negative retry period
if (RetryPeriod <= 0)
{
return;
}
_retryPeriod = value;
}
}
public event Action<Exception> Error;
public event Action<string> Received;
public event Action Closed;
public event Action Reconnecting;
public event Action Reconnected;
public event Action ConnectionSlow;
public event Action<StateChange> StateChanged;
private HubConnectionManager()
{
_retryTimer = new Timer(async state => await RetryConnection(state), null, Timeout.Infinite, RetryPeriod);
}
public static IHubConnectionManager GetHubConnectionmanager(string url)
{
IHubConnectionManager connectionManager = new HubConnectionManager();
connectionManager.Initialize(url);
return connectionManager;
}
public async Task Initialize(string url)
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException("url");
}
if (_hubConnection != null)
{
//Already intialized
return;
}
try
{
_hubConnection = new HubConnection(url);
_hubConnection.Received += s => { if (Received != null) { Received(s); } };
_hubConnection.Closed += () => { if (Closed != null) { Closed(); } };
_hubConnection.Reconnecting += () => { if (Reconnecting != null) { Reconnecting(); } };
_hubConnection.Reconnected += () => { if (Reconnected != null) { Reconnected(); } };
_hubConnection.ConnectionSlow += () => { if (ConnectionSlow != null) { ConnectionSlow(); } };
_hubConnection.Error += e => { if (Error != null) { Error(e); } };
_hubConnection.StateChanged += OnStateChanged;
await _hubConnection.Start();
}
catch (Exception ex) { /*Om nom nom*/ }
}
public IHubProxy CreateHubProxy(string hubName)
{
if (string.IsNullOrEmpty(hubName))
{
throw new ArgumentNullException("hubName");
}
if (_hubConnection == null)
{
throw new InvalidOperationException("Please execute Initialize() method perior to CreateHubProxy");
}
return _hubConnection.CreateHubProxy(hubName);
}
private void OnStateChanged(StateChange stateChange)
{
try
{
if (stateChange.NewState == ConnectionState.Connected || stateChange.NewState == ConnectionState.Connecting || stateChange.NewState == ConnectionState.Reconnecting)
{
_retryTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
else
{
_retryTimer.Change(RetryPeriod, RetryPeriod);
}
}
catch (Exception) { /* Om nom nom */ }
finally
{
//Bubble event up to higher-level subscribers;
if (StateChanged != null)
{
StateChanged(stateChange);
}
}
}
private async Task RetryConnection(object state)
{
try
{
if (_hubConnection != null && _hubConnection.State == ConnectionState.Disconnected)
{
await _hubConnection.Start();
}
}
catch (Exception ex) { /*Om nom nom*/ }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment