如何使用aspnetcore signalR向特定用户发送消息?

时间:2020-02-18 07:04:57

标签: c# signalr signalr-hub asp.net-core-signalr

我有向特定用户发送通知的要求。我正在使用dotnet core 3.1。通知的ASPNETCORE signalR。 我能够将邮件发送给所有客户端,但绝对不能针对特定用户发送邮件。

编辑1

我的集线器看起来像:

public class NotificationHub : Hub
{
    public override async Task OnConnectedAsync()
    {
        await Groups.AddToGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
        await base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception ex)
    {
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
        await base.OnDisconnectedAsync(ex);
    }
}

我正在从Controller调用SendAsync方法为:

 private IHubContext<NotificationHub> _hub;

    public NotificationController(IHubContext<NotificationHub> hub)
    {
        _hub = hub;
    }

[HttpGet]
    public IActionResult Get()
    {
        //_hub.Clients.All.SendAsync("SendMessage",
        _hub.Clients.All.SendAsync("SendMessage",
            new
            {
                val1 = getRandomString(),
                val2 = getRandomString(),
                val3 = getRandomString(),
                val4 = getRandomString()
            });

        return Ok(new { Message = "Request Completed" });
    }

3 个答案:

答案 0 :(得分:1)

您可以通过user id

向特定用户发送消息

在此示例中,我们将尝试获取当前用户信息,并使用用户ID将一些数据发送回该用户:

在中心:

public async Task GetInfo()
{
    var user = await _userManager.GetUserAsync(Context.User);

    await Clients.User(user.Id).SendCoreAsync("msg", new object[] { user.Id, user.Email });
}

在客户端中:

connection.on('msg', function (...data) {
    console.log('data:', data); // ["27010e2f-a47f-4c4e-93af-b55fd95f48a5", "foo@bar.com"]
});

connection.start().then(function () {
    connection.invoke('getinfo');
});

注意:请确保您已经在UseEndpoints方法内映射了中心:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");

    endpoints.MapHub<YourHubName>("/yourhubname");
});

答案 1 :(得分:1)

如果您知道用户connectionId或将连接的用户添加到组中,则可以将通知发送到指定的人。

在中心,假设您知道connectionId:

await this.Clients.Client("connectionId").SendAsync("MethodName", "The message");

您还可以将指定的用户添加到组中,然后将消息发送到该组:

await this.Groups.AddToGroupAsync("connectionId", "groupName");

await this.Clients.Group("groupName").SendAsync("MethodName", "The message");

您可以在此Microsoft Documentation中了解更多信息。

更新:

要回答更新的问题,必须向中心提供授权属性,以便具有身份名称和其他参数

[Authorize]
public class NotificationHub : Hub
{
    public override async Task OnConnectedAsync()
    {
        await Groups.AddToGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
        await base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception ex)
    {
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
        await base.OnDisconnectedAsync(ex);
    }
}

然后在Angular客户端上,您必须提供令牌以连接到集线器,例如:

private configureSignalR(token: string) {
    this.hubMessageConnection = new signalR.HubConnectionBuilder()
    .configureLogging(signalR.LogLevel.Error).withUrl(this.signalRUrl + "/notifications",
    {
        accessTokenFactory: () => token
    })
    .withAutomaticReconnect()
    .build();
}

您可以了解有关Authentication and authorization in the microsoft documentation的更多信息。

答案 2 :(得分:0)

我认为是ASP.NET Core SignalR中的错误(我也在使用ASP.NET Core 3.1 ),

_hubContext.Clients.User(userId).SendAsync(...)

似乎不起作用。请注意,默认情况下,userId是基于声明的身份验证存储为ClaimTypes.NameIdentifier的内容( From doc:默认情况下,SignalR使用与连接关联的ClaimsPrincipal中的ClaimTypes.NameIdentifier作为用户标识符。

所以我不得不创建自己的连接管理器,并且运行良好,一旦获得所有用户的连接,就可以循环并编写类似的内容

_hubContext.Clients.Client(connectionId).SendAsync(...)

以下是有关如何管理用户连接的提示:

public class YourHub : Hub
        ...
        public override Task OnConnectedAsync()
        {    
            //Get userId
            _connectionHubManager.AddConnection(userId, Context.ConnectionId);
            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            _connectionHubManager.RemoveConnection(Context.ConnectionId);
            return base.OnDisconnectedAsync(exception);
        }

获得userId取决于您的努力。

如果将userId注册为ClaimTypes.Name,则只需获取它:

Context.User.Identity.Name;

如果将userId注册为ClaimTypes.NameIdentifier,则需要执行以下操作:

(Context.User.Identity as ClaimsIdentity)?.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value;

不要忘记将[Authorize]添加到您的集线器类中,以填充这些字段并检查Doc以获得SignalR身份验证。