如何通过SignalR将消息发送给特定用户(身份标识)?
问题描述:
在我Startup.Auth.cs
:如何通过SignalR将消息发送给特定用户(身份标识)?
private static void ConfigSignalR(IAppBuilder appBuilder)
{
appBuilder.MapSignalR();
var idProvider = new PrincipalUserIdProvider();
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider),() => idProvider);
}
我UserHub.cs
:
public class UserHub : Hub
{
}
在服务器端,在我的API控制器动作之一(与网格更新认沽):
[...]
var userHub = GlobalHost.ConnectionManager.GetHubContext<UserHub>();
// Line below does not work
// userHub.Clients.User(userId).send("Hi");
// But this line below works when sending the message to everybody
userHub.Clients.All.send("Hi");
return Request.CreateResponse(HttpStatusCode.OK);
在JS View客户端:
@Request.IsAuthenticated
{
<script>
$(function() {
var userHub = $.connection.userHub;
console.log(userHub.client);
userHub.client.send = function(message) {
alert('received: ' + message);
};
$.connection.hub.start().done(function() {
});
});
</script>
}
为什么在通过userId
时我的客户端收不到任何东西? (也尝试通过userName
,结果相同)。
[编辑] 技术上实现了正确的方法是充分利用IUserIdProvider
执行:
- https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/mapping-users-to-connections#IUserIdProvider
- SignalR - Sending a message to a specific user using (IUserIdProvider) *NEW 2.0.0*
然而,我注意到,在我如果传递给GetUserId
方法的IRequest对象的User
属性始终设置为null
...
答
的解决方案实际上已经给出了另外一个问题,就在这里:https://stackoverflow.com/a/22028296/4636721
的问题是所有关于在Startup.Auth.cs
初始化顺序: SignalR必须饼干后进行初始化和OwinContext
初始化,如IUserIdProvider
传递给GlobalHost.DependencyResolver.Register
接收包含IRequest
一个非空User
其GetUserId
方法:
public partial class Startup
{
public void ConfigureAuth(IAppBuilder appBuilder)
{
// Order matters here...
// Otherwise SignalR won't get Identity User information passed to Id Provider...
ConfigOwinContext(appBuilder);
ConfigCookies(appBuilder);
ConfigSignalR(appBuilder);
}
private static void ConfigOwinContext(IAppBuilder appBuilder)
{
appBuilder.CreatePerOwinContext(ApplicationDbContext.Create);
appBuilder.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
appBuilder.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
appBuilder.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
appBuilder.CreatePerOwinContext(LdapAdEmailAuthenticator.Create);
}
private static void ConfigCookies(IAppBuilder appBuilder)
{
appBuilder.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>
(
TimeSpan.FromHours(4),
(manager, user) => user.GenerateUserIdentityAsync(manager)
)
}
});
appBuilder.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
appBuilder.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
appBuilder.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
private static void ConfigSignalR(IAppBuilder appBuilder)
{
appBuilder.MapSignalR();
var idProvider = new HubIdentityUserIdProvider();
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider),() => idProvider);
}
}
使用IUserIdProvider
下面,我明确宣布,我要使用的用户ID,而不是用户名由IUserIdProvider
的缺省实现给定,又名PrincipalUserIdProvider
:
public class HubIdentityUserIdProvider : IUserIdProvider
{
public string GetUserId(IRequest request)
{
return request == null
? throw new ArgumentNullException(nameof(request))
: request.User?.Identity?.GetUserId();
}
}
我的理解是最简单,最干净的方式做到这一点是将客户端和连接存储在OnConnected方法内的字典中。用户基于随机生成的连接ID,因此您传递的任何内容都不会匹配。 – willthiswork89