c# - SignalR .NET 客户端:排除连接时跨连接处理广播
问题描述
我正在为我的 SignalR 集线器编写单元测试并使用 SignalR .NET 客户端(版本 2.3.0)执行测试,但是当当前连接从广播中排除时,我无法让其他连接接收广播.
hub 方法是这样进行广播的:
Clients.Group(groupName, Context.ConnectionId).sendMessage("A message");
我的测试配置为有 2 个到集线器的连接,每个连接都将调用一个集线器方法,该方法将把连接放入groupName
. 然后我有一个HubConnection.On
事件来处理集线器方法进行的广播,然后使用其结果来断言测试。这在代码中可能会更清楚地解释(为简洁起见,我删除了一些 AddBroadcast 重载):
/// <summary>
/// Class to handle the connection, calling of methods and broadcast for a SignalR hub
/// </summary>
public class HubManager
{
public enum Froms
{
Other1,
Other2
}
private HubConnection hubConnection = null;
private IHubProxy hub = null;
/// <summary>
/// The outcome of the broadcast that is made
/// </summary>
public object Result { get; private set; } = null;
/// <summary>
/// The connection ID of this hub connection
/// </summary>
public string ConnectionID { get { return this.hubConnection.ConnectionId; } }
public HubManager(string h)
{
//Create the SignalR connection
this.hubConnection = new HubConnection("http://mywebsite.com");
//Gain access to the hub
this.hub = hubConnection.CreateHubProxy(h);
//Start the connection up and wait for it to complete
this.hubConnection.Start()
.ContinueWith(task =>
{
if (task.IsFaulted)
{
throw new Exception($"Error opening the hub connection ({h}): {task.Exception.GetBaseException()}");
}
})
.Wait();
}
/// <summary>
/// Broadcast a message to clients
/// </summary>
/// <param name="methodName">The name of broadcast message</param>
public void AddBroadcast(string methodName)
{
this.hub.On(methodName, () => {
this.Result = methodName;
});
}
/// <summary>
/// Broadcast a message to clients
/// </summary>
/// <param name="methodName">The name of broadcast message</param>
public void AddBroadcast<T>(string methodName)
{
this.hub.On<T>(methodName, _1 => {
this.Result = _1;
});
}
/// <summary>
/// Invokes a specific hub method
/// </summary>
/// <param name="methodName">The name of the hub method to invoke</param>
/// <param name="args">The parameters for the method</param>
public void CallMethod(string methodName, params object[] args)
{
this.hub.Invoke(methodName, args)
.ContinueWith(task =>
{
if (task.IsFaulted)
{
throw new Exception($"Error calling hub method {methodName}: {task.Exception.GetBaseException()}");
}
})
.Wait();
}
}
使用案例:
//Create a dictionary to hold the connections
var hubManagers = new Dictionary<HubManager.Froms, HubManager>();
hubManagers.Add(HubManager.Froms.Other1, new HubManager(hubName));
hubManagers.Add(HubManager.Froms.Other2, new HubManager(hubName));
//Call HubMethod1 which will add the connection to the same group
hubManagers[HubManager.Froms.Other1].CallMethod("HubMethod1", user1ID);
hubManagers[HubManager.Froms.Other2].CallMethod("HubMethod1", user2ID);
//Set a broadcast handle for the second connection (Other2)
hubManagers[HubManager.Froms.Other2].AddBroadcast<string, string>("callbackMethod");
//Make a hub method call (from Other1) to cause the callbackMethod to run
//As from above, the Other1 connection should not receive it but Other2 should
hubManagers[HubManager.Froms.Other1].CallMethod("HubMethod2", user1ID);
//Get the broadcast result for the second connection (Other2)
var result = hubManagers[HubManager.Froms.Other2].Result;
//result == null
我尝试使用AdddBroadcast
以下组合,每种情况都会导致result
null Other1
:Other2
和Other1
& Other2
。
如果我更改Clients.Group(groupName, Context.ConnectionId).sendMessage("A message");
为不排除当前连接 ( Clients.Group(groupName).sendMessage("A message");
) 并使用AddBroadcast
on Other2
,result
则包含预期值。
该过程在实时系统(使用 ASP.NET 和 JavaScript)上按预期工作,其中调用连接不会被发送,sendMessage
但组的其他成员会发送。
当第一个连接从广播中排除时,我如何让第二个 SignalR .NET 客户端连接接收广播的任何想法都非常受欢迎!
解决方案
一段时间后,我意识到this.hub.On
事件正在触发,但在调用后获取结果(var result = hubManagers[HubManager.Froms.Other2].Result;
)。因此,我添加了一个粗略的等待方法(我并不为此感到非常自豪!),这已经成功了。
新方法:
/// <summary>
/// Wait for up to 5 seconds for the broadcast to complete
/// </summary>
public void WaitForBroadcastResult()
{
bool stop = false;
const double WAIT_FOR = 5D;
DateTime started = DateTime.Now;
while (!stop)
{
if (this.Result != null || (DateTime.Now - started).TotalSeconds >= WAIT_FOR)
{
stop = true;
}
else
{
System.Threading.Thread.Sleep(100);
}
}
}
利用:
...
//Set a broadcast handle for the second connection (Other2)
hubManagers[HubManager.Froms.Other2].AddBroadcast<string, string>("callbackMethod");
//Make a hub method call (from Other1) to cause the callbackMethod to run
//As from above, the Other1 connection should not receive it but Other2 should
hubManagers[HubManager.Froms.Other1].CallMethod("HubMethod2", user1ID);
//Wait for the broadcast to complete
this.HubManagers[_HubManager.Froms.Other2].WaitForBroadcastResult();
//Get the broadcast result for the second connection (Other2)
var result = hubManagers[HubManager.Froms.Other2].Result;
如果有人有更好的主意,那么我全神贯注!
推荐阅读
- ubuntu - Flask + UWSGI + NGinx = 504 超时,除了 root
- c# - 使用我的 c# 应用程序从谷歌浏览器中获取文本
- sql - 在加入时使用case语句根据条件执行查询
- android - 无法从中加载模块元数据
- javascript - 访问 vue 实例上的外部 js 文件
- java - 每日滚动限制使用 logj4 的备份文件
- excel - 每组具有值和计算字段行的数据透视表列?
- wordpress - 带有 and , or 条件的 Wordpress 分类查询
- javascript - 从移动设备共享时,移动博客网站未重定向到桌面
- html - IPAD pro 中选择选项下拉列表的问题