Support for Others and Caller Client Subsets(#1192)
This commit is contained in:
parent
c0b9ae5e55
commit
75e102f97a
|
|
@ -18,7 +18,6 @@ namespace ChatSample.Hubs
|
||||||
public override async Task OnConnectedAsync()
|
public override async Task OnConnectedAsync()
|
||||||
{
|
{
|
||||||
await Clients.Client(Context.ConnectionId).InvokeAsync("SetUsersOnline", await GetUsersOnline());
|
await Clients.Client(Context.ConnectionId).InvokeAsync("SetUsersOnline", await GetUsersOnline());
|
||||||
|
|
||||||
await base.OnConnectedAsync();
|
await base.OnConnectedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ namespace ChatSample
|
||||||
_hubContext = _serviceProvider.GetRequiredService<IHubContext<THub>>();
|
_hubContext = _serviceProvider.GetRequiredService<IHubContext<THub>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
hub.Clients = _hubContext.Clients;
|
hub.Clients = new HubCallerClients(_hubContext.Clients, connection.ConnectionId);
|
||||||
hub.Context = new HubCallerContext(connection);
|
hub.Context = new HubCallerContext(connection);
|
||||||
hub.Groups = _hubContext.Groups;
|
hub.Groups = _hubContext.Groups;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,19 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
{
|
{
|
||||||
public class DynamicHubClients
|
public class DynamicHubClients
|
||||||
{
|
{
|
||||||
private readonly IHubClients _clients;
|
private readonly IHubCallerClients _clients;
|
||||||
|
|
||||||
public DynamicHubClients(IHubClients clients)
|
public DynamicHubClients(IHubCallerClients clients)
|
||||||
{
|
{
|
||||||
_clients = clients;
|
_clients = clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
public dynamic All => new DynamicClientProxy(_clients.All);
|
public dynamic All => new DynamicClientProxy(_clients.All);
|
||||||
public dynamic AllExcept(IReadOnlyList<string> excludedIds) => new DynamicClientProxy(_clients.AllExcept(excludedIds));
|
public dynamic AllExcept(IReadOnlyList<string> excludedIds) => new DynamicClientProxy(_clients.AllExcept(excludedIds));
|
||||||
public dynamic User(string userId) => new DynamicClientProxy(_clients.User(userId));
|
public dynamic Caller => new DynamicClientProxy(_clients.Caller);
|
||||||
public dynamic Group(string group) => new DynamicClientProxy(_clients.Group(group));
|
|
||||||
public dynamic Client(string connectionId) => new DynamicClientProxy(_clients.Client(connectionId));
|
public dynamic Client(string connectionId) => new DynamicClientProxy(_clients.Client(connectionId));
|
||||||
|
public dynamic Group(string group) => new DynamicClientProxy(_clients.Group(group));
|
||||||
|
public dynamic Others => new DynamicClientProxy(_clients.Others);
|
||||||
|
public dynamic User(string userId) => new DynamicClientProxy(_clients.User(userId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,11 +9,11 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
public class Hub : IDisposable
|
public class Hub : IDisposable
|
||||||
{
|
{
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private IHubClients _clients;
|
private IHubCallerClients _clients;
|
||||||
private HubCallerContext _context;
|
private HubCallerContext _context;
|
||||||
private IGroupManager _groups;
|
private IGroupManager _groups;
|
||||||
|
|
||||||
public IHubClients Clients
|
public IHubCallerClients Clients
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR
|
||||||
|
{
|
||||||
|
public class HubCallerClients : IHubCallerClients
|
||||||
|
{
|
||||||
|
private string _connectionId;
|
||||||
|
private IHubClients _hubClients;
|
||||||
|
private string[] _currentConnectionId;
|
||||||
|
|
||||||
|
public HubCallerClients(IHubClients hubClients, string connectionId)
|
||||||
|
{
|
||||||
|
_connectionId = connectionId;
|
||||||
|
_hubClients = hubClients;
|
||||||
|
_currentConnectionId = new string[] { _connectionId };
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClientProxy Caller => _hubClients.Client(_connectionId);
|
||||||
|
|
||||||
|
public IClientProxy Others => _hubClients.AllExcept(_currentConnectionId);
|
||||||
|
|
||||||
|
public IClientProxy All => _hubClients.All;
|
||||||
|
|
||||||
|
public IClientProxy AllExcept(IReadOnlyList<string> excludedIds)
|
||||||
|
{
|
||||||
|
return _hubClients.AllExcept(excludedIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClientProxy Client(string connectionId)
|
||||||
|
{
|
||||||
|
return _hubClients.Client(connectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClientProxy Group(string groupName)
|
||||||
|
{
|
||||||
|
return _hubClients.Group(groupName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClientProxy User(string userId)
|
||||||
|
{
|
||||||
|
return _hubClients.User(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -368,7 +368,7 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
|
|
||||||
private void InitializeHub(THub hub, HubConnectionContext connection)
|
private void InitializeHub(THub hub, HubConnectionContext connection)
|
||||||
{
|
{
|
||||||
hub.Clients = _hubContext.Clients;
|
hub.Clients = new HubCallerClients(_hubContext.Clients, connection.ConnectionId);
|
||||||
hub.Context = new HubCallerContext(connection);
|
hub.Context = new HubCallerContext(connection);
|
||||||
hub.Groups = _hubContext.Groups;
|
hub.Groups = _hubContext.Groups;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
{
|
{
|
||||||
public class Hub<T> : Hub where T : class
|
public class Hub<T> : Hub where T : class
|
||||||
{
|
{
|
||||||
private IHubClients<T> _clients;
|
private IHubCallerClients<T> _clients;
|
||||||
|
|
||||||
public new IHubClients<T> Clients
|
public new IHubCallerClients<T> Clients
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +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.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR
|
||||||
|
{
|
||||||
|
public interface IHubCallerClients : IHubCallerClients<IClientProxy> { }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR
|
||||||
|
{
|
||||||
|
public interface IHubCallerClients<T> : IHubClients<T>
|
||||||
|
{
|
||||||
|
T Caller { get; }
|
||||||
|
|
||||||
|
T Others { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// 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.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.SignalR
|
namespace Microsoft.AspNetCore.SignalR
|
||||||
{
|
{
|
||||||
|
|
@ -20,3 +18,4 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
T User(string userId);
|
T User(string userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,32 +5,36 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.SignalR
|
namespace Microsoft.AspNetCore.SignalR
|
||||||
{
|
{
|
||||||
internal class TypedHubClients<T> : IHubClients<T>
|
internal class TypedHubClients<T> : IHubCallerClients<T>
|
||||||
{
|
{
|
||||||
private IHubClients hubClients;
|
private IHubCallerClients _hubClients;
|
||||||
|
|
||||||
public TypedHubClients(IHubClients dynamicContext)
|
public TypedHubClients(IHubCallerClients dynamicContext)
|
||||||
{
|
{
|
||||||
hubClients = dynamicContext;
|
_hubClients = dynamicContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T All => TypedClientBuilder<T>.Build(hubClients.All);
|
public T All => TypedClientBuilder<T>.Build(_hubClients.All);
|
||||||
|
|
||||||
public T AllExcept(IReadOnlyList<string> excludedIds) => TypedClientBuilder<T>.Build(hubClients.AllExcept(excludedIds));
|
public T Caller => TypedClientBuilder<T>.Build(_hubClients.Caller);
|
||||||
|
|
||||||
|
public T Others => TypedClientBuilder<T>.Build(_hubClients.Others);
|
||||||
|
|
||||||
|
public T AllExcept(IReadOnlyList<string> excludedIds) => TypedClientBuilder<T>.Build(_hubClients.AllExcept(excludedIds));
|
||||||
|
|
||||||
public T Client(string connectionId)
|
public T Client(string connectionId)
|
||||||
{
|
{
|
||||||
return TypedClientBuilder<T>.Build(hubClients.Client(connectionId));
|
return TypedClientBuilder<T>.Build(_hubClients.Client(connectionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Group(string groupName)
|
public T Group(string groupName)
|
||||||
{
|
{
|
||||||
return TypedClientBuilder<T>.Build(hubClients.Group(groupName));
|
return TypedClientBuilder<T>.Build(_hubClients.Group(groupName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public T User(string userId)
|
public T User(string userId)
|
||||||
{
|
{
|
||||||
return TypedClientBuilder<T>.Build(hubClients.User(userId));
|
return TypedClientBuilder<T>.Build(_hubClients.User(userId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -826,6 +826,84 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(HubTypes))]
|
||||||
|
public async Task SendToOthers(Type hubType)
|
||||||
|
{
|
||||||
|
var serviceProvider = CreateServiceProvider();
|
||||||
|
|
||||||
|
dynamic endPoint = serviceProvider.GetService(GetEndPointType(hubType));
|
||||||
|
|
||||||
|
using (var firstClient = new TestClient())
|
||||||
|
using (var secondClient = new TestClient())
|
||||||
|
{
|
||||||
|
Task firstEndPointTask = endPoint.OnConnectedAsync(firstClient.Connection);
|
||||||
|
Task secondEndPointTask = endPoint.OnConnectedAsync(secondClient.Connection);
|
||||||
|
|
||||||
|
await Task.WhenAll(firstClient.Connected, secondClient.Connected).OrTimeout();
|
||||||
|
|
||||||
|
await firstClient.SendInvocationAsync("SendToOthers", "To others").OrTimeout();
|
||||||
|
|
||||||
|
var secondClientResult = await secondClient.ReadAsync().OrTimeout();
|
||||||
|
var invocation = Assert.IsType<InvocationMessage>(secondClientResult);
|
||||||
|
Assert.Equal("Send", invocation.Target);
|
||||||
|
Assert.Equal("To others", invocation.Arguments[0]);
|
||||||
|
|
||||||
|
var firstClientResult = await firstClient.ReadAsync().OrTimeout();
|
||||||
|
var completion = Assert.IsType<CompletionMessage>(firstClientResult);
|
||||||
|
|
||||||
|
await secondClient.SendInvocationAsync("BroadcastMethod", "To everyone").OrTimeout();
|
||||||
|
firstClientResult = await firstClient.ReadAsync().OrTimeout();
|
||||||
|
invocation = Assert.IsType<InvocationMessage>(firstClientResult);
|
||||||
|
Assert.Equal("Broadcast", invocation.Target);
|
||||||
|
Assert.Equal("To everyone", invocation.Arguments[0]);
|
||||||
|
|
||||||
|
// kill the connections
|
||||||
|
firstClient.Dispose();
|
||||||
|
secondClient.Dispose();
|
||||||
|
|
||||||
|
await Task.WhenAll(firstEndPointTask, secondEndPointTask).OrTimeout();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(HubTypes))]
|
||||||
|
public async Task SendToCaller(Type hubType)
|
||||||
|
{
|
||||||
|
var serviceProvider = CreateServiceProvider();
|
||||||
|
|
||||||
|
dynamic endPoint = serviceProvider.GetService(GetEndPointType(hubType));
|
||||||
|
|
||||||
|
using (var firstClient = new TestClient())
|
||||||
|
using (var secondClient = new TestClient())
|
||||||
|
{
|
||||||
|
Task firstEndPointTask = endPoint.OnConnectedAsync(firstClient.Connection);
|
||||||
|
Task secondEndPointTask = endPoint.OnConnectedAsync(secondClient.Connection);
|
||||||
|
|
||||||
|
await Task.WhenAll(firstClient.Connected, secondClient.Connected).OrTimeout();
|
||||||
|
|
||||||
|
await firstClient.SendInvocationAsync("SendToCaller", "To caller").OrTimeout();
|
||||||
|
|
||||||
|
var firstClientResult = await firstClient.ReadAsync().OrTimeout();
|
||||||
|
var invocation = Assert.IsType<InvocationMessage>(firstClientResult);
|
||||||
|
Assert.Equal("Send", invocation.Target);
|
||||||
|
Assert.Equal("To caller", invocation.Arguments[0]);
|
||||||
|
|
||||||
|
await firstClient.SendInvocationAsync("BroadcastMethod", "To everyone").OrTimeout();
|
||||||
|
var secondClientResult = await secondClient.ReadAsync().OrTimeout();
|
||||||
|
invocation = Assert.IsType<InvocationMessage>(secondClientResult);
|
||||||
|
Assert.Equal("Broadcast", invocation.Target);
|
||||||
|
Assert.Equal("To everyone", invocation.Arguments[0]);
|
||||||
|
|
||||||
|
// kill the connections
|
||||||
|
firstClient.Dispose();
|
||||||
|
|
||||||
|
await firstEndPointTask.OrTimeout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(HubTypes))]
|
[MemberData(nameof(HubTypes))]
|
||||||
public async Task SendToAllExcept(Type hubType)
|
public async Task SendToAllExcept(Type hubType)
|
||||||
|
|
@ -1557,6 +1635,16 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
{
|
{
|
||||||
return Clients.AllExcept(excludedIds).Send(message);
|
return Clients.AllExcept(excludedIds).Send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task SendToOthers(string message)
|
||||||
|
{
|
||||||
|
return Clients.Others.Send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendToCaller(string message)
|
||||||
|
{
|
||||||
|
return Clients.Caller.Send(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Test
|
public interface Test
|
||||||
|
|
@ -1735,6 +1823,16 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
{
|
{
|
||||||
return Clients.AllExcept(excludedIds).Send(message);
|
return Clients.AllExcept(excludedIds).Send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task SendToOthers(string message)
|
||||||
|
{
|
||||||
|
return Clients.Others.Send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendToCaller(string message)
|
||||||
|
{
|
||||||
|
return Clients.Caller.Send(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StreamingHub : TestHub
|
public class StreamingHub : TestHub
|
||||||
|
|
@ -1930,6 +2028,16 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
||||||
{
|
{
|
||||||
return Context.Connection.GetHttpContext() != null;
|
return Context.Connection.GetHttpContext() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task SendToOthers(string message)
|
||||||
|
{
|
||||||
|
return Clients.Others.InvokeAsync("Send", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendToCaller(string message)
|
||||||
|
{
|
||||||
|
return Clients.Caller.InvokeAsync("Send", message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class InheritedHub : BaseHub
|
private class InheritedHub : BaseHub
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue