115

In the latest version of Asp.Net SignalR, was added a new way of sending a message to a specific user, using the interface "IUserIdProvider".

public interface IUserIdProvider
{
   string GetUserId(IRequest request);
}

public class MyHub : Hub
{
   public void Send(string userId, string message)
   {
      Clients.User(userId).send(message);
   }
}

My question is: How do I know to whom I am sending my message? The explanation of this new method is very superficial. And the draft Statement of SignalR 2.0.0 with this bug and does not compile. Has anyone implemented this feature?

More Info : http://www.asp.net/signalr/overview/signalr-20/hubs-api/mapping-users-to-connections#IUserIdProvider

Hugs.

4

6 回答 6

171

SignalR 为每个连接提供 ConnectionId。要找到哪个连接属于谁(用户),我们需要在连接和用户之间创建一个映射。这取决于您如何在应用程序中识别用户。

在 SignalR 2.0 中,这是通过使用 inbuilt 来完成的IPrincipal.Identity.Name,这是在 ASP.NET 身份验证期间设置的登录用户标识符。

但是,您可能需要使用不同的标识符而不是使用 Identity.Name 来映射与用户的连接。为此,此新提供程序可与您的自定义实现一起使用,以将用户映射到连接。

使用 IUserIdProvider 将 SignalR 用户映射到连接的示例

假设我们的应用程序使用 auserId来识别每个用户。现在,我们需要向特定用户发送消息。我们有userIdand message,但 SignalR 还必须知道我们的 userId 和连接之间的映射。

为此,首先我们需要创建一个新类,它实现IUserIdProvider

public class CustomUserIdProvider : IUserIdProvider
{
     public string GetUserId(IRequest request)
    {
        // your logic to fetch a user identifier goes here.

        // for example:

        var userId = MyCustomUserClass.FindUserId(request.User.Identity.Name);
        return userId.ToString();
    }
}

第二步是告诉 SignalR 使用我们的CustomUserIdProvider而不是默认实现。这可以在初始化集线器配置时在 Startup.cs 中完成:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var idProvider = new CustomUserIdProvider();

        GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);          

        // Any connection or hub wire up and configuration should go here
        app.MapSignalR();
    }
}

userId现在,您可以使用文档中提到的特定用户向特定用户发送消息,例如:

public class MyHub : Hub
{
   public void Send(string userId, string message)
   {
      Clients.User(userId).send(message);
   }
}

希望这可以帮助。

于 2014-01-25T19:47:09.213 回答
45

这是一个开始.. 对建议/改进持开放态度。

服务器

public class ChatHub : Hub
{
    public void SendChatMessage(string who, string message)
    {
        string name = Context.User.Identity.Name;
        Clients.Group(name).addChatMessage(name, message);
        Clients.Group("2@2.com").addChatMessage(name, message);
    }

    public override Task OnConnected()
    {
        string name = Context.User.Identity.Name;
        Groups.Add(Context.ConnectionId, name);

        return base.OnConnected();
    }
}

JavaScript

(注意上面服务器代码中的方法addChatMessage和方法)sendChatMessage

    $(function () {
    // Declare a proxy to reference the hub.
    var chat = $.connection.chatHub;
    // Create a function that the hub can call to broadcast messages.
    chat.client.addChatMessage = function (who, message) {
        // Html encode display name and message.
        var encodedName = $('<div />').text(who).html();
        var encodedMsg = $('<div />').text(message).html();
        // Add the message to the page.
        $('#chat').append('<li><strong>' + encodedName
            + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
    };

    // Start the connection.
    $.connection.hub.start().done(function () {
        $('#sendmessage').click(function () {
            // Call the Send method on the hub.
            chat.server.sendChatMessage($('#displayname').val(), $('#message').val());
            // Clear text box and reset focus for next comment.
            $('#message').val('').focus();
        });
    });
});

测试 在此处输入图像描述

于 2014-01-19T20:36:52.597 回答
8

这就是使用 SignarR 来定位特定用户的方式(不使用任何提供者):

 private static ConcurrentDictionary<string, string> clients = new ConcurrentDictionary<string, string>();

 public string Login(string username)
 {
     clients.TryAdd(Context.ConnectionId, username);            
     return username;
 }

// The variable 'contextIdClient' is equal to Context.ConnectionId of the user, 
// once logged in. You have to store that 'id' inside a dictionaty for example.  
Clients.Client(contextIdClient).send("Hello!");
于 2018-04-05T15:30:15.297 回答
2

查看SignalR 测试以了解该功能。

测试“SendToUser”自动获取通过使用常规 owin 身份验证库传递的用户身份。

场景是您有一个用户从多个设备/浏览器连接,并且您希望将消息推送到他的所有活动连接。

于 2013-10-22T16:10:13.750 回答
1

旧线程,但只是在示例中遇到了这个:

services.AddSignalR()
            .AddAzureSignalR(options =>
        {
            options.ClaimsProvider = context => new[]
            {
                new Claim(ClaimTypes.NameIdentifier, context.Request.Query["username"])
            };
        });
于 2020-07-17T21:20:50.893 回答
0

对于任何试图在 asp.net 核心中执行此操作的人。您可以使用声明。

public class CustomEmailProvider : IUserIdProvider
{
    public virtual string GetUserId(HubConnectionContext connection)
    {
        return connection.User?.FindFirst(ClaimTypes.Email)?.Value;
    }
}

可以使用任何标识符,但它必须是唯一的。例如,如果您使用名称标识符,这意味着如果有多个用户与收件人同名,则消息也会发送给他们。我选择了电子邮件,因为它对每个用户都是独一无二的。

然后在启动类中注册服务。

services.AddSingleton<IUserIdProvider, CustomEmailProvider>();

下一个。在用户注册期间添加声明。

var result = await _userManager.CreateAsync(user, Model.Password);
if (result.Succeeded)
{
    await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Email, Model.Email));
}

向特定用户发送消息。

public class ChatHub : Hub
{
    public async Task SendMessage(string receiver, string message)
    {
        await Clients.User(receiver).SendAsync("ReceiveMessage", message);
    }
}

注意:消息发送者不会被通知消息已发送。如果您想在发件人端收到通知。把SendMessage方法改成这个。

public async Task SendMessage(string sender, string receiver, string message)
{
    await Clients.Users(sender, receiver).SendAsync("ReceiveMessage", message);
}

仅当您需要更改默认标识符时,才需要执行这些步骤。否则,跳到最后一步,您可以通过将 userIds 或 connectionIds 传递给简单地发送消息SendMessage更多

于 2020-09-07T04:54:08.450 回答