检查群组是否包含任何客户端

问题描述 投票:0回答:1

背景

我有以下工作流程让服务器从连接的客户端查询数据:

// Server-side code
async Task<string> RequestDataFromClient(string groupName)
{
    var responseId = GenerateUniqueId();

    // let the clients know that we want something
    await hubContext.Clients.Group(groupName).Request(responseId);

    try
    {
        return await WaitForIncomingCall(responseId);
    }
    catch(TimeoutException)
    {
        return GetDataFromFallbackMethod();
    }
}

服务器首先向给定 SignalR 组中的所有客户端发送

Request
。然后,它等待任何客户端使用
Respond
调用具有给定
responseId
WaitForIncomingCall
hub 方法。
WaitForIncomingCall
有以下签名

Task<string> WaitForIncomingCall(responseId)

如果一段时间后没有客户端调用

Respond
hub 方法,
WaitForIncomingCall
会抛出
TimeoutException
。如果发生此类异常,服务器将使用回退方法来检索数据(例如,从缓存中)。

问题

如果给定的SignalR组中不存在客户端,服务器将等待直到超过超时时间,直到启动回退方法。这会给

RequestDataFromClient
的调用者带来明显的延迟。如果 SignalR 组中没有客户端,我宁愿直接调用后备方法。因此,如果没有人可以回应,就不要问。

问题

如何查明 SignalR 组是否为空或者

Request
调用是否可能已到达连接的客户端?一旦负载平衡发挥作用,手动跟踪连接似乎不是一个好主意。

asp.net-core signalr
1个回答
3
投票

据我所知,目前Asp.net core SignalR没有内置方法来检查组是否为空或组中是否存在客户端。而从官方文档中,我们还可以发现:

重新连接连接时,不会保留组成员身份。重新建立连接后需要重新加入组。无法计算组的成员数量,因为如果应用程序扩展到多个服务器,则此信息不可用。

要检查组是否包含任何已连接的客户端,作为解决方法,在 hub 方法中,您可以定义一个全局变量来存储组名称和在线计数,也可以存储用户信息(用户名、组名称、在线状态等)在数据库中。

然后,在 OnConnectedAsync 方法中,您可以将用户添加到组中并计算在线人数或更改用户的在线状态,在 OnDisconnectedAsync 方法中从组中删除用户并更改在线用户数。创建自定义方法来检查/获取在线用户数。

这样的代码(在这个示例代码中,我使用登录用户名来创建组,您可以根据您的场景更改它):

[Authorize]
public class ChatHub : Hub
{
    private static Dictionary<string, int> onlineClientCounts = new Dictionary<string, int>();

    public override Task OnConnectedAsync()
    { 
        var IdentityName = Context.User.Identity.Name;
        Groups.AddToGroupAsync(Context.ConnectionId, IdentityName);

        int count = 0;
        if (onlineClientCounts.TryGetValue(IdentityName, out count))
            onlineClientCounts[IdentityName] = count + 1;//increment client number
        else
            onlineClientCounts.Add(IdentityName, 1);// add group and set its client number to 1


        return base.OnConnectedAsync();
    }
    public async Task SendMessage(string user, string message)
    { 
        
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }

    public async Task SendMessageToGroup(string sender, string groupname, string message)
    { 
        //check if group contains clients or not via the global variable or check database.

        await Clients.Group(groupname).SendAsync("ReceiveMessage", sender, message);
    }

    public override async Task OnDisconnectedAsync(Exception exception)
    {
        var IdentityName = Context.User.Identity.Name;
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, IdentityName);

        int count = 0;
        if (onlineClientCounts.TryGetValue(IdentityName, out count))
        {
            if (count == 1)//if group contains only 1client
                onlineClientCounts.Remove(IdentityName);
            else
                onlineClientCounts[IdentityName] = count - 1;
        } 

        await base.OnDisconnectedAsync(exception);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.