Invoke Users (#1257)

This commit is contained in:
Mikael Mengistu 2018-01-08 17:58:42 -08:00 committed by GitHub
parent a6f30623d8
commit 89b532c985
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 135 additions and 4 deletions

View File

@ -186,5 +186,10 @@ namespace ChatSample
{
return _wrappedHubLifetimeManager.InvokeGroupExceptAsync(groupName, methodName, args, excludedIds);
}
public override Task InvokeUsersAsync(IReadOnlyList<string> userIds, string methodName, object[] args)
{
return _wrappedHubLifetimeManager.InvokeUsersAsync(userIds, methodName, args);
}
}
}

View File

@ -208,5 +208,13 @@ namespace Microsoft.AspNetCore.SignalR
return connectionIds.Contains(connection.ConnectionId);
});
}
public override Task InvokeUsersAsync(IReadOnlyList<string> userIds, string methodName, object[] args)
{
return InvokeAllWhere(methodName, args, connection =>
{
return userIds.Contains(connection.UserIdentifier);
});
}
}
}

View File

@ -25,5 +25,6 @@ namespace Microsoft.AspNetCore.SignalR
public dynamic OthersInGroup(string groupName) => new DynamicClientProxy(_clients.OthersInGroup(groupName));
public dynamic Others => new DynamicClientProxy(_clients.Others);
public dynamic User(string userId) => new DynamicClientProxy(_clients.User(userId));
public dynamic Users(IReadOnlyList<string> users) => new DynamicClientProxy(_clients.Users(users));
}
}

View File

@ -63,5 +63,10 @@ namespace Microsoft.AspNetCore.SignalR
{
return _hubClients.Clients(connectionIds);
}
public IClientProxy Users(IReadOnlyList<string> userIds)
{
return _hubClients.Users(userIds);
}
}
}

View File

@ -51,5 +51,10 @@ namespace Microsoft.AspNetCore.SignalR
{
return new UserProxy<THub>(_lifetimeManager, userId);
}
public IClientProxy Users(IReadOnlyList<string> userIds)
{
return new MultipleUserProxy<THub>(_lifetimeManager, userIds);
}
}
}

View File

@ -1,9 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.AspNetCore.SignalR
{
@ -53,5 +51,10 @@ namespace Microsoft.AspNetCore.SignalR
{
return TypedClientBuilder<T>.Build(new UserProxy<THub>(_lifetimeManager, userId));
}
public virtual T Users(IReadOnlyList<string> userIds)
{
return TypedClientBuilder<T>.Build(new MultipleUserProxy<THub>(_lifetimeManager, userIds));
}
}
}

View File

@ -28,6 +28,8 @@ namespace Microsoft.AspNetCore.SignalR
public abstract Task InvokeUserAsync(string userId, string methodName, object[] args);
public abstract Task InvokeUsersAsync(IReadOnlyList<string> userIds, string methodName, object[] args);
public abstract Task AddGroupAsync(string connectionId, string groupName);
public abstract Task RemoveGroupAsync(string connectionId, string groupName);

View File

@ -22,6 +22,8 @@ namespace Microsoft.AspNetCore.SignalR
T GroupExcept(string groupName, IReadOnlyList<string> excludeIds);
T User(string userId);
T Users(IReadOnlyList<string> userIds);
}
}

View File

@ -23,6 +23,23 @@ namespace Microsoft.AspNetCore.SignalR
}
}
public class MultipleUserProxy<THub> : IClientProxy
{
private readonly IReadOnlyList<string> _userIds;
private readonly HubLifetimeManager<THub> _lifetimeManager;
public MultipleUserProxy(HubLifetimeManager<THub> lifetimeManager, IReadOnlyList<string> userIds)
{
_lifetimeManager = lifetimeManager;
_userIds = userIds;
}
public Task InvokeAsync(string method, params object[] args)
{
return _lifetimeManager.InvokeUsersAsync(_userIds, method, args);
}
}
public class GroupProxy<THub> : IClientProxy
{
private readonly string _groupName;

View File

@ -56,5 +56,10 @@ namespace Microsoft.AspNetCore.SignalR
{
return TypedClientBuilder<T>.Build(_hubClients.User(userId));
}
public T Users(IReadOnlyList<string> userIds)
{
return TypedClientBuilder<T>.Build(_hubClients.Users(userIds));
}
}
}

View File

@ -621,6 +621,26 @@ namespace Microsoft.AspNetCore.SignalR.Redis
return Task.WhenAll(publishTasks);
}
public override Task InvokeUsersAsync(IReadOnlyList<string> userIds, string methodName, object[] args)
{
if (userIds.Count > 0)
{
var message = new RedisInvocationMessage(methodName, args);
var publishTasks = new List<Task>(userIds.Count);
foreach (var userId in userIds)
{
if (!string.IsNullOrEmpty(userId))
{
publishTasks.Add(PublishAsync(_channelNamePrefix + ".user." + userId, message));
}
}
return Task.WhenAll(publishTasks);
}
return Task.CompletedTask;
}
private class LoggerTextWriter : TextWriter
{
private readonly ILogger _logger;

View File

@ -22,6 +22,11 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
return Clients.User(userId).InvokeAsync("Send", message);
}
public Task SendToMultipleUsers(IReadOnlyList<string> userIds, string message)
{
return Clients.Users(userIds).InvokeAsync("Send", message);
}
public Task ConnectionSendMethod(string connectionId, string message)
{
return Clients.Client(connectionId).InvokeAsync("Send", message);
@ -181,6 +186,11 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
return Clients.User(userId).Send(message);
}
public Task SendToMultipleUsers(IReadOnlyList<string> userIds, string message)
{
return Clients.Users(userIds).Send(message);
}
public Task ConnectionSendMethod(string connectionId, string message)
{
return Clients.Client(connectionId).Send(message);
@ -256,6 +266,11 @@ namespace Microsoft.AspNetCore.SignalR.Tests.HubEndpointTestUtils
return Clients.User(userId).Send(message);
}
public Task SendToMultipleUsers(IReadOnlyList<string> userIds, string message)
{
return Clients.Users(userIds).Send(message);
}
public Task ConnectionSendMethod(string connectionId, string message)
{
return Clients.Client(connectionId).Send(message);

View File

@ -956,8 +956,6 @@ namespace Microsoft.AspNetCore.SignalR.Tests
var secondAndThirdClients = new HashSet<string> {secondClient.Connection.ConnectionId,
thirdClient.Connection.ConnectionId };
secondAndThirdClients.Add(secondClient.Connection.ConnectionId);
await firstClient.SendInvocationAsync("SendToMultipleClients", "Second and Third", secondAndThirdClients).OrTimeout();
var secondClientResult = await secondClient.ReadAsync().OrTimeout();
@ -984,6 +982,51 @@ namespace Microsoft.AspNetCore.SignalR.Tests
}
}
[Theory]
[MemberData(nameof(HubTypes))]
public async Task SendToMultipleUsers(Type hubType)
{
dynamic endPoint = HubEndPointTestUtils.GetHubEndpoint(hubType);
using (var firstClient = new TestClient(addClaimId: true))
using (var secondClient = new TestClient(addClaimId: true))
using (var thirdClient = new TestClient(addClaimId: true))
{
Task firstEndPointTask = endPoint.OnConnectedAsync(firstClient.Connection);
Task secondEndPointTask = endPoint.OnConnectedAsync(secondClient.Connection);
Task thirdEndPointTask = endPoint.OnConnectedAsync(thirdClient.Connection);
await Task.WhenAll(firstClient.Connected, secondClient.Connected, thirdClient.Connected).OrTimeout();
var secondAndThirdClients = new HashSet<string> {secondClient.Connection.User.FindFirst(ClaimTypes.NameIdentifier)?.Value,
thirdClient.Connection.User.FindFirst(ClaimTypes.NameIdentifier)?.Value };
await firstClient.SendInvocationAsync(nameof(MethodHub.SendToMultipleUsers), secondAndThirdClients, "Second and Third").OrTimeout();
var secondClientResult = await secondClient.ReadAsync().OrTimeout();
var invocation = Assert.IsType<InvocationMessage>(secondClientResult);
Assert.Equal("Send", invocation.Target);
Assert.Equal("Second and Third", invocation.Arguments[0]);
var thirdClientResult = await thirdClient.ReadAsync().OrTimeout();
invocation = Assert.IsType<InvocationMessage>(thirdClientResult);
Assert.Equal("Send", invocation.Target);
Assert.Equal("Second and Third", invocation.Arguments[0]);
// Check that first client only got the completion message
var hubMessage = await firstClient.ReadAsync().OrTimeout();
Assert.IsType<CompletionMessage>(hubMessage);
Assert.Null(firstClient.TryRead());
// kill the connections
firstClient.Dispose();
secondClient.Dispose();
thirdClient.Dispose();
await Task.WhenAll(firstEndPointTask, secondEndPointTask, thirdEndPointTask).OrTimeout();
}
}
[Theory]
[MemberData(nameof(HubTypes))]
public async Task HubsCanAddAndSendToGroup(Type hubType)