private async Task HubOnDisconnectedAsync(HubConnectionContext connection, Exception?exception) { // send close message before aborting the connection await SendCloseAsync(connection, exception, connection.AllowReconnect); // We wait on abort to complete, this is so that we can guarantee that all callbacks have fired // before OnDisconnectedAsync // Ensure the connection is aborted before firing disconnect await connection.AbortAsync(); try { await _dispatcher.OnDisconnectedAsync(connection, exception); } catch (Exception ex) { Log.ErrorDispatchingHubEvent(_logger, "OnDisconnectedAsync", ex); throw; } }
private async Task RunHubAsync(HubConnectionContext connection) { try { await _dispatcher.OnConnectedAsync(connection); } catch (Exception ex) { Log.ErrorDispatchingHubEvent(_logger, "OnConnectedAsync", ex); // The client shouldn't try to reconnect given an error in OnConnected. await SendCloseAsync(connection, ex, allowReconnect : false); // return instead of throw to let close message send successfully return; } try { await DispatchMessagesAsync(connection); } catch (OperationCanceledException) { // Don't treat OperationCanceledException as an error, it's basically a "control flow" // exception to stop things from running } catch (Exception ex) { Log.ErrorProcessingRequest(_logger, ex); await HubOnDisconnectedAsync(connection, ex); // return instead of throw to let close message send successfully return; } await HubOnDisconnectedAsync(connection, connection.CloseException); }