【问题标题】:How to send a SignalR message to a user?如何向用户发送 SignalR 消息?
【发布时间】:2021-09-13 19:19:01
【问题描述】:

客户端如何授权向用户发送消息?

从控制器发送

hubContext.Clients.User(User.Identity.Name).SendAsync();

此时消息未发送。我需要在 OnConnection() 中添加一些东西吗?或者 SignalR 有没有现成的 ConnectionId 和 User.Identity.Name 的映射机制?

这就是我目前实现它的方式,但在我看来并不完全正确。问题是如何制作相同的标准工具?

    public static class HubConnections
{
    public static Dictionary<string, List<string>> Users = new Dictionary<string, List<string>>();

    public static List<string> GetUserId(string name)
    {
        return Users[name];
    }
}

public class GameHub : Hub
{
    public override Task OnConnectedAsync()
    {


        if (Context.User.Identity.IsAuthenticated 
            && HubConnections.Users.ContainsKey(Context.User.Identity.Name) 
            && !HubConnections.Users[Context.User.Identity.Name].Contains(Context.ConnectionId))
                HubConnections.Users[Context.User.Identity.Name].Add(Context.ConnectionId);
        else 
            HubConnections.Users.Add(Context.User.Identity.Name, new List<string> { Context.ConnectionId });

        return base.OnConnectedAsync();
    }

    public override Task OnDisconnectedAsync(Exception exception)
    {
        if (Context.User.Identity.IsAuthenticated) HubConnections.Users.Remove(Context.User.Identity.Name);

        return base.OnDisconnectedAsync(exception);
    }
}

上面说了,我就这样试了,还是不行

hubContext.Clients.User(User.Identity.Name).SendAsync();

【问题讨论】:

  • 请查看文档,它的解释和记录都很好:docs.microsoft.com/en-us/aspnet/core/tutorials/…
  • 重读不止一次。我没有找到必要的信息
  • 问题非常广泛,我们需要更多代码,请展示您尝试过的内容,可能有问题的类更详细。
  • 已更新,请查看

标签: asp.net-core signalr


【解决方案1】:

正在追同样的问题,并从https://github.com/aspnet/SignalR/issues/2498得到解决方案

需要设置 NameIdentifier 声明。那是 SignalR 检查的,而不是我假设的 Name 声明。我设置了 NameIdentifier 声明,并让我的非集线器类向特定用户发送通知。

【讨论】:

    【解决方案2】:

    有一个客户端组件。您必须引用 SignalR JS 文件,创建连接,然后订阅来自服务器的特定消息。只有这样发送该消息才会真正起作用。

    <script src="~/lib/signalr/signalr.js"></script>
    <script>
        const connection = new signalR.HubConnectionBuilder()
           .withUrl("/gameHub")
           .configureLogging(signalR.LogLevel.Information)
           .build();
    
        connection.on("Foo", (data) => {
            // do something
        });
    
        connection.start().catch(err => console.error(err.toString()));
    </script>
    

    每当服务器发送"Foo" 消息时,上面将导致客户端运行上面为"Foo" 定义的函数:

    hubContext.Clients.User(User.Identity.Name).SendAsync("Foo", data);
    

    【讨论】:

    • 谢谢,但已经完成了。问题出在用户身上。例如,如果我这样做 Clients.All,那么一切正常并触发事件,但 Client.User (User.Identity.Name) 被忽略
    • 如果您的用户实际通过了身份验证?
    • 是的,已授权。并且 User.Identity.Name 存储它的用户名
    【解决方案3】:

    您正在使用Users 作为连接ID 的存储。因此,对于每个用户名,您可以将消息发送到您为该用户存储的每个客户端连接。像这样的:

    public void SendMessage(string username, object data)
    {
        var connections = HubConnections.Users[Context.User.Identity.Name];
    
        foreach(var id in connections)
        {
            Clients.client(id).SendAsync("Foo", data);
        }
    }
    

    【讨论】:

    • 是的,但我正在尝试使用 Clients.User(用户名),这就是它不起作用的原因。我已经实现了你描述的方法,但它有点错误,我的
    【解决方案4】:

    signalR 用于识别用户的声明可以更改。确保此声明具有唯一值非常重要。

    文档说要像这样设置自定义 UserIdProvider:

    public class NameUserIdProvider : IUserIdProvider
    {
        public string GetUserId(HubConnectionContext connection)
        {
            return connection.User?.Identity?.Name;
        }
    }
    

    添加然后将其添加到服务中:

    public void ConfigureServices(IServiceCollection services)
    {
        // ... other services ...
    
        services.AddSignalR();
        services.AddSingleton<IUserIdProvider, NameUserIdProvider>();
    }
    

    sn-ps 取自官方文档: https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-3.1#use-claims-to-customize-identity-handling

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-27
      • 1970-01-01
      • 2013-04-16
      • 1970-01-01
      相关资源
      最近更新 更多