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


101

在最新版本的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);
   }
}

我的问题是:我怎么知道我要向谁发送消息?这种新方法的解释非常肤浅。而SignalR 2.0.0的声明草案带有此错误,无法编译。有人实现了此功能吗?

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

拥抱


1
您需要使用SignalR查看身份验证和授权。UserId将成为IPrincipal提供程序的一部分。
Gjohn 2014年

Answers:


153

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

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

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

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

假设我们的应用程序使用a userId来标识每个用户。现在,我们需要向特定用户发送消息。我们有userIdmessage,但是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);
   }
}

希望这可以帮助。


嗨,朋友,很抱歉收到您的反馈意见!但是我试图访问生成CustomUserIdProvider的ID,但“ OnConnected”方法却不相同。如何链接到数据库中的用户?谢谢!
伊戈尔(Igor)2014年

7
什么是MyCustomUserClass?
丹尼·布利斯

2
“ MyCustomUserClass”可以是您的自定义用户类,其中包含FindUserId方法。这只是举例。您可以在任何可返回UserId的类中使用任何方法,并在此处使用该方法。
Sumant'Apr

5
谢谢@Sumant,我的问题最终是因为b / c是我在一个Web API项目中,我用承载令牌实现了OAuth 2,所以我必须实现逻辑以在查询字符串上传递承载令牌,因为无法从查询字符串中提取承载令牌该初始信号器连接请求上的标头。无法只使用request.User.Identity.Name
xinunix

1
@Sumant我已经解决了。问题是我app.MapSignalR();在身份验证之前放入了global.asax。
机器人先生

38

这是一个开始。欢迎您提出建议/改进。

服务器

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();
        });
    });
});

测验 在此处输入图片说明


嗨,朋友,很抱歉收到您的反馈意见!但是如何防止CONNECTIONID丢失?谢谢。
伊戈尔(Igor)

5
@lgao我不知道。
松饼人2014年

为什么需要此行--- Clients.Group(“ 2@2.com”)。addChatMessage(name,message); ??
汤玛斯(Thomas)

@Thomas我可能出于演示目的将其包括在内。由于已硬编码,因此必须有另一种向特定组广播的方法。
松饼人

这个简单的解决方案解决了我的问题,向特定的登录用户发送消息。它简单,快速且易于理解。如果可以的话,我会多次投票赞成这个答案。
拉斐尔AMS

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!");

2
您是如何使用这个contextIdClient没得到它:(

2

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

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

该方案是您有一个从多个设备/浏览器进行连接的用户,并且希望将消息推送到其所有活动连接。


谢啦!但是项目版本2.0不在此处编译SignalR。:(。不幸的是我无法访问它
Igor

0

旧线程,但在示例中遇到了这个问题:

services.AddSignalR()
            .AddAzureSignalR(options =>
        {
            options.ClaimsProvider = context => new[]
            {
                new Claim(ClaimTypes.NameIdentifier, context.Request.Query["username"])
            };
        });
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.