首页 > 解决方案 > 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以下组合,每种情况都会导致resultnull Other1:Other2Other1& Other2

如果我更改Clients.Group(groupName, Context.ConnectionId).sendMessage("A message");为不排除当前连接 ( Clients.Group(groupName).sendMessage("A message");) 并使用AddBroadcaston Other2result则包含预期值。

该过程在实时系统(使用 ASP.NET 和 JavaScript)上按预期工作,其中调用连接不会被发送,sendMessage但组的其他成员会发送。

当第一个连接从广播中排除时,我如何让第二个 SignalR .NET 客户端连接接收广播的任何想法都非常受欢迎!

标签: c#signalr.client

解决方案


一段时间后,我意识到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;

如果有人有更好的主意,那么我全神贯注!


推荐阅读