// Tasks and message are passed by ref so they can be lazily created inside the method post-filtering, // while still being re-usable when sending to multiple groups private static void SendToGroupConnections(string methodName, object?[] args, ConcurrentDictionary <string, HubConnectionContext> connections, Func <HubConnectionContext, object?, bool>?include, object?state, ref List <Task>?tasks, ref SerializedHubMessage?message, CancellationToken cancellationToken) { // foreach over ConcurrentDictionary avoids allocating an enumerator foreach (var connection in connections) { if (include != null && !include(connection.Value, state)) { continue; } if (message == null) { message = DefaultHubLifetimeManager <THub> .CreateSerializedInvocationMessage(methodName, args); } var task = connection.Value.WriteAsync(message, cancellationToken); if (!task.IsCompletedSuccessfully) { if (tasks == null) { tasks = new List <Task>(); } tasks.Add(task.AsTask()); } else { // If it's a IValueTaskSource backed ValueTask, // inform it its result has been read so it can reset task.GetAwaiter().GetResult(); } } }
private Task SendToAllConnections(string methodName, object?[] args, Func <HubConnectionContext, object?, bool>?include, object?state = null, CancellationToken cancellationToken = default) { List <Task>? tasks = null; SerializedHubMessage?message = null; // foreach over HubConnectionStore avoids allocating an enumerator foreach (var connection in _connections) { if (include != null && !include(connection, state)) { continue; } if (message == null) { message = DefaultHubLifetimeManager <THub> .CreateSerializedInvocationMessage(methodName, args); } var task = connection.WriteAsync(message, cancellationToken); if (!task.IsCompletedSuccessfully) { if (tasks == null) { tasks = new List <Task>(); } tasks.Add(task.AsTask()); } else { // If it's a IValueTaskSource backed ValueTask, // inform it its result has been read so it can reset task.GetAwaiter().GetResult(); } } if (tasks == null) { return(Task.CompletedTask); } // Some connections are slow return(Task.WhenAll(tasks)); }