SignalR - 使用(IUserIdProvider)*NEW 2.0.0*向特定用户发送消息

Igo*_*gor 91 asp.net asp.net-mvc real-time signalr

在最新版本的Asp.Net SignalR中,添加了一种使用"IUserIdProvider"接口向特定用户发送消息的新方法.

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

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

我的问题是:我如何知道我向谁发送信息?这种新方法的解释非常肤浅.SignalR 2.0.0的声明草案带有这个bug并且没有编译.有没有人实现过这个功能?

更多信息:http://www.asp.net/signalr/overview/signalr-20/hubs-api/mapping-users-to-connections#IUserIdProvider

拥抱.

Sum*_*ant 143

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

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

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

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

让我们假设我们的应用程序使用a userId来识别每个用户.现在,我们需要向特定用户发送消息.我们有userIdmessage,但是SignalR还必须知道我们的帐户及连接之间的映射.

要实现这一点,首先我们需要创建一个实现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();
    }
}
Run Code Online (Sandbox Code Playgroud)

第二步是告诉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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

希望这可以帮助.

  • 什么是MyCustomUserClass? (5认同)
  • 谢谢@Sumant,我的问题最终是b/c我在一个Web API项目中我用承载令牌实现了OAuth 2我必须实现逻辑以在查询字符串上传递bearer token,因为它不能从初始信号器上的标头连接请求.不能只使用request.User.Identity.Name (5认同)
  • “ MyCustomUserClass”可以是您的自定义用户类,其中包含FindUserId方法。这只是举例。您可以在任何可返回UserId的类中使用任何方法,并在此处使用该方法。 (2认同)

The*_*Man 37

这是一个开始..接受建议/改进.

服务器

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

JavaScript的

(注意上面的服务器代码中的方法addChatMessagesendChatMessage方法)

    $(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();
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

测试 在此输入图像描述

  • @lgao我不知道. (3认同)

Mat*_*lio 5

这是使用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!");
Run Code Online (Sandbox Code Playgroud)

  • 你如何使用这个`contextIdClient` 没有得到它:( (3认同)

Qud*_*dus 5

对于任何尝试在 ASP.NET Core 中执行此操作的人。您可以使用声明。

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

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

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

services.AddSingleton<IUserIdProvider, CustomEmailProvider>();
Run Code Online (Sandbox Code Playgroud)

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

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

向特定用户发送消息。

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

注意:消息发送者不会收到消息已发送的通知。如果您希望在发件人端收到通知。将SendMessage方法改为这样。

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

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