Fluffymittens
Fluffymittens

Reputation: 180

SignalR .Net client async reconnect

My WPF app is running locally using SignalR .Net Client to connect to the SignalR hub with async code.

I would like to solve the case that the SignalR hub goes down and the WPF app automatically reconnects when the SignalR hub comes back online after for example 10 minutes. I would like to register an async action to the HubConnection closed event. The automated SignalR reconnect logic is awesome but when that timeout is exceeded it should still reconnect to the hub. The example is using Polly to retry until success after the connection was closed.

The issue with following code is that there is no control over the async action (HubConnectionClosedEventHandler) and when closing the WPF app it doesn't properly dispose those running tasks. There is also the strange behavior that Log4Net stops logging after a few retries. What is the best practice for registering an async action to the closed event to try to reconnect ? What am I doing wrong ?

private async Task InitializeAsync()
{
   this.hubConnection.Closed += this.HubConnectionClosedEventHandler();
}

private Action HubConnectionClosedEventHandler()
{
    return () => this.HubConnectionClosed().Wait();
}

private async Task HubConnectionClosed()
{
    App.LogDebug("Connection closed event triggered.");
    await this.StartSignalRConnection();
}

private async Task StartSignalRConnection()
{
    App.LogDebug("Initialize policy.");
    var policy = Policy.Handle<Exception>().WaitAndRetryForeverAsync(retryAttempt => TimeSpan.FromSeconds(2));
    await policy.ExecuteAsync(this.StartSignalRConnectionAsync);
 }

private async Task StartSignalRConnectionAsync()
{
    App.LogDebug("Start connection.");
    await this.hubConnection.Start()
                .ContinueWith(
                    task =>
                        {
                            if (task.Exception != null || task.IsFaulted)
                            {
                                var exceptionMessage =
                                    $"There was an error opening the connection with connection '{CustomSettings.CallcenterHubConnection}'";
                                App.LogError(exceptionMessage,
                                    task.Exception);
                                throw new InvalidOperationException(exceptionMessage);
                            }

                            App.LogDebug(
                                $"Connected successfully with connection '{CustomSettings.CallcenterHubConnection}'");
                        });
}

public void Stop()
{
    try
    {
        this.hubConnection.Closed -= this.HubConnectionClosedEventHandler();
        if (this.hubConnection.State != ConnectionState.Disconnected) this.hubConnection.Stop();
    }
    catch (Exception ex)
    {
        App.LogError("Exception when stopping", ex);
    }
}

Upvotes: 1

Views: 1469

Answers (1)

Fluffymittens
Fluffymittens

Reputation: 180

It seems that hijacking the closed event for a reconnect is just wrong. In the end we ended up changing the disconnect timeout to 5 minutes and visualizing the WPF tool with a disconnect icon. If the server had some serious issue and is fixed then the user manually must restart the WPF tool.

Upvotes: 1

Related Questions