将SignalR连接映射到用户

时间:2012-12-25 18:17:05

标签: asp.net notifications signalr signalr-hub

考虑像facebook这样的网络应用程序,它可以向用户发送实时通知。

使用asp.net SignalR跟踪哪个连接ID属于哪个用户的最佳方法是什么,即使用户断开连接或稍后重新连接?

4 个答案:

答案 0 :(得分:26)

查看以下博文:

Mapping ASP.NET SignalR Connections to Real Application Users

简而言之,您将在OnConnected方法上向用户添加连接ID,并在OnDisconnected方法中删除该连接。请记住,应用程序用户可以拥有多个连接。因此,您需要在用户和连接ID之间建立一对多的关系。以上链接的帖子详细解释了它的样本。

答案 1 :(得分:6)

我为内部应用做了这个。我这样做的方式是当用户连接时,我让服务器要求用户注册自己。这样我知道不仅用户连接了他们的signalR connnectionID,而且他们还可以告诉我任何其他信息(如用户名或其他)。

当他们重新连接时,我要求他们再做一次。

SignalR将为每个客户端维护相同的connectionID,即使它们重新连接也很好。重新连接与初始连接不同。新连接表示新客户端,但重新连接在同一客户端上。

在我的应用程序中,我维护了一个单独的线程安全字典,我跟踪哪个用户和哪个connectionID正在做什么。这样我可以说“哦,向用户ABC发送消息”并查找其connectionID。然后在signalR中为该connectionID执行Hub的客户端对象。如果你这样做,你甚至可以在mutliple连接中拥有相同的“用户”。想象一下,用户“abc”在两个浏览器选项卡中打开。如果你严格按照connectionID进行操作,那么他们在技术上就是两个不同的用户。但是,通过维护某种本地集合分组用户和连接,您现在可以为同一用户建立多个连接。

我应该提一下,如果你这样做,你应该确保你的网站处理重启时会发生什么,并丢失所有的连接信息。对我来说,当有人重新连接时,我要求他们再次重新认识自己。这样,当服务器上线时我可以重新构建我的本地字典而不用担心。它确实有更多的开销,因为现在您要求所有客户向您发送信息,但根据您的用户情况,这可能会交错或聚集或以其他方式分发以帮助您处理负载。

一般情况下,无论您获取本地信息(无论是要求用户提供),还是通过http上下文会话信息,您都需要自己跟踪。

答案 2 :(得分:3)

我使用了不同的方法,我扩展了ApplicationUser类:

    // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
    //public int ApplicationUserId { get; set; }
    //public string Name { get; set; }
    //public string Address { get; set; }
    //public string City { get; set; }
    //public string State { get; set; }
    //public string Zip { get; set; }
    [Required]
    public string Email { get; set; }
    [Required]
    public override string UserName { get; set; }
    [NotMapped]
    public string ConnectionId { get; set; }
    [NotMapped]
    public string ChattingUserConnectionId { get; set; }
    //public string HomeTown { get; set; }
    //public DateTime? BirthDate { get; set; }
}

在我的中心,我做了类似的事情:

public class ChatHub : Hub
{
    #region Data Members
    private static ApplicationDbContext applicationDbContext = new ApplicationDbContext();
    private static UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(applicationDbContext));
    private static List<ApplicationUser> connectedUsers = new List<ApplicationUser>();

当用户连接到聊天时,我通过他的用户名获取他的ApplicationUser对象并将其添加到connectedUsers列表中。当他断开连接时,我将他移除。

我遇到了EF状态的一些随机异常,这使我每次访问时都会创建ApplicationDbContext和UserManager,而不是在静态对象中设置它:

 private ApplicationUser GetCurrentUser()
    {
        ApplicationDbContext applicationDbContext = new ApplicationDbContext();
        UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(applicationDbContext));
        var userName = Context.User.Identity.GetUserName();
        var user = userManager.FindByName<ApplicationUser>(userName);

        return user;
    }

编辑:

集线器代码在加载用户的子对象时遇到一些问题。此代码也在asp.net模板中使用,效果更好,不需要ApplicationDBContext:

    private ApplicationUserManager _userManager
    {
        get
        {
            return HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
    }


    var user = _userManager.FindByName<ApplicationUser, string>(userName);

答案 3 :(得分:0)

有关ASP.NET的SignalR教程部分的非常好的文章。 我已经在下面介绍了段落。

  

Mapping SignalR Users to Connections

     

连接到集线器的每个客户端都会传递唯一的连接ID。您可以   在集线器的Context.ConnectionId属性中检索此值   上下文。如果您的应用程序需要将用户映射到连接ID   并坚持该映射,您可以使用以下之一:

     
      
  • 用户ID提供商(SignalR 2)
  •   
  • 内存存储,例如字典
  •   
  • 每个用户的SignalR组
  •   
     

永久的外部存储,例如数据库表或Azure表   存储本主题中显示了这些实现中的每一个。你用   集线器的OnConnected,OnDisconnected和OnReconnected方法   用于跟踪用户连接状态的类。


UserID提供商

如果您正在使用ASP.NET的标准成员资格提供程序(IPrincipal.Identity.Name),则可以执行以下操作以基于用户帐户访问客户端。如果您有自己的用户系统,则可以创建自己的提供商。

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