如何通过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执行:

然而,我注意到,在我如果传递给GetUserId方法的IRequest对象的User属性始终设置为null ...

+1

我的理解是最简单,最干净的方式做到这一点是将客户端和连接存储在OnConnected方法内的字典中。用户基于随机生成的连接ID,因此您传递的任何内容都不会匹配。 – willthiswork89

的解决方案实际上已经给出了另外一个问题,就在这里:https://*.com/a/22028296/4636721

的问题是所有关于在Startup.Auth.cs初始化顺序: SignalR必须饼干后进行初始化和OwinContext初始化,如IUserIdProvider传递给GlobalHost.DependencyResolver.Register接收包含IRequest一个非空UserGetUserId方法:

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