在最新版本的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的声明草案带有这个bug并且没有编译。有没有人实现过这个功能?
更多信息:http://www.asp.net/signalr/overview/signalr-20/hubs-api/mapping-users-to-connections#IUserIdProvider
拥抱。
答案 0 :(得分:135)
SignalR为每个连接提供ConnectionId。要查找哪个连接属于谁(用户),我们需要在连接和用户之间创建映射。这取决于您在应用程序中识别用户的方式。
在SignalR 2.0中,这是通过使用内置的IPrincipal.Identity.Name
来完成的,这是在ASP.NET身份验证期间设置的登录用户标识符。
但是,您可能需要使用不同的标识符而不是使用Identity.Name来映射与用户的连接。为此,这个新的提供程序可以与您的自定义实现一起使用,以便通过连接映射用户。
让我们假设我们的应用程序使用userId
来识别每个用户。现在,我们需要向特定用户发送消息。我们有userId
和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);
}
}
希望这有帮助。
答案 1 :(得分:34)
这是一个开始......接受建议/改进。
服务器
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>: ' + 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();
});
});
});
测试
答案 2 :(得分:3)
这是使用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!");
答案 3 :(得分:2)
答案 4 :(得分:0)
旧线程,但在示例中遇到了这个问题:
services.AddSignalR()
.AddAzureSignalR(options =>
{
options.ClaimsProvider = context => new[]
{
new Claim(ClaimTypes.NameIdentifier, context.Request.Query["username"])
};
});
答案 5 :(得分: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);
}
仅当您需要更改默认标识符时,才需要执行这些步骤。否则,跳到最后一步,您可以通过将userId或connectionId传递到SendMessage
来简单地发送消息。 For more