如何向用户发送SignalR消息?

6
客户端如何授权向用户发送消息?
控制器发送。
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();

多次重读后,我没有找到必要的信息。 - Vanik Hachatryan
问题非常广泛,我们需要更多的代码,请展示您尝试过的内容,以及可能存在问题的类别和更多细节。 - Mohammed Noureldin
更新了,请检查。 - Vanik Hachatryan
4个回答

3

我曾经遇到同样的问题,从https://github.com/aspnet/SignalR/issues/2498上找到了解决方案。

需要设置NameIdentifier声明。这是SignalR检查的声明,而不是我假设的Name声明。我设置了NameIdentifier声明,我的非hub类就可以向特定用户发送通知。


1
信号R用于标识用户的声明可以更改。确保该声明具有唯一值非常重要。
文档中指出,设置自定义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>();
}

这些片段来自官方文档: https://learn.microsoft.com/zh-cn/aspnet/core/signalr/authn-and-authz?view=aspnetcore-3.1#use-claims-to-customize-identity-handling

0

有一个客户端组件。您必须引用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)会被忽略。 - Vanik Hachatryan
用户是否已经通过身份验证? - Chris Pratt
是的,它已被授权。User.Identity.Name 存储了它的用户名。 - Vanik Hachatryan

0

您正在使用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(用户名),这就是为什么它不起作用的原因。我已经实施了您描述的方法,但它似乎有问题,我的。 - Vanik Hachatryan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接